3 * oFono - Open Source Telephony
5 * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
33 #include <ofono/log.h>
34 #include <ofono/modem.h>
35 #include <ofono/sim.h>
38 #include "gatresult.h"
44 #define EF_STATUS_INVALIDATED 0
45 #define EF_STATUS_VALID 1
47 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
55 static const char *crsm_prefix[] = { "+CRSM:", NULL };
56 static const char *cpin_prefix[] = { "+CPIN:", NULL };
57 static const char *clck_prefix[] = { "+CLCK:", NULL };
58 static const char *huawei_cpin_prefix[] = { "^CPIN:", NULL };
59 static const char *xpincnt_prefix[] = { "+XPINCNT:", NULL };
60 static const char *none_prefix[] = { NULL };
62 static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
64 struct cb_data *cbd = user_data;
66 ofono_sim_file_info_cb_t cb = cbd->cb;
67 struct ofono_error error;
68 const guint8 *response;
72 unsigned char access[3];
73 unsigned char file_status;
75 decode_at_error(&error, g_at_result_final_response(result));
78 cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
82 g_at_result_iter_init(&iter, result);
84 if (!g_at_result_iter_next(&iter, "+CRSM:"))
87 g_at_result_iter_next_number(&iter, &sw1);
88 g_at_result_iter_next_number(&iter, &sw2);
90 if (!g_at_result_iter_next_hexstring(&iter, &response, &len) ||
91 (sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92) ||
92 (sw1 == 0x90 && sw2 != 0x00)) {
93 memset(&error, 0, sizeof(error));
95 error.type = OFONO_ERROR_TYPE_SIM;
96 error.error = (sw1 << 8) | sw2;
98 cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
102 DBG("crsm_info_cb: %02x, %02x, %i", sw1, sw2, len);
104 if (response[0] == 0x62) {
105 ok = sim_parse_3g_get_response(response, len, &flen, &rlen,
108 file_status = EF_STATUS_VALID;
111 ok = sim_parse_2g_get_response(response, len, &flen, &rlen,
112 &str, access, &file_status);
117 cb(&error, flen, str, rlen, access, file_status, cbd->data);
122 CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
123 EF_STATUS_INVALIDATED, cbd->data);
126 static void at_sim_read_info(struct ofono_sim *sim, int fileid,
127 ofono_sim_file_info_cb_t cb,
130 struct sim_data *sd = ofono_sim_get_data(sim);
134 if (sd->vendor == OFONO_VENDOR_OPTION_HSO) {
135 unsigned char access[3] = { 0x00, 0x00, 0x00 };
137 if (fileid == SIM_EFAD_FILEID) {
138 CALLBACK_WITH_SUCCESS(cb, 4, 0, 0, access,
139 EF_STATUS_VALID, data);
144 cbd = cb_data_new(cb, data);
148 snprintf(buf, sizeof(buf), "AT+CRSM=192,%i", fileid);
150 switch (sd->vendor) {
151 case OFONO_VENDOR_HUAWEI:
152 case OFONO_VENDOR_QUALCOMM_MSM:
153 strcat(buf, ",0,0,255"); /* Maximum possible length */
157 if (g_at_chat_send(sd->chat, buf, crsm_prefix,
158 at_crsm_info_cb, cbd, g_free) > 0)
162 CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
163 EF_STATUS_INVALIDATED, data);
166 static void at_crsm_read_cb(gboolean ok, GAtResult *result,
169 struct cb_data *cbd = user_data;
171 ofono_sim_read_cb_t cb = cbd->cb;
172 struct ofono_error error;
173 const guint8 *response;
176 decode_at_error(&error, g_at_result_final_response(result));
179 cb(&error, NULL, 0, cbd->data);
183 g_at_result_iter_init(&iter, result);
185 if (!g_at_result_iter_next(&iter, "+CRSM:")) {
186 CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
190 g_at_result_iter_next_number(&iter, &sw1);
191 g_at_result_iter_next_number(&iter, &sw2);
193 if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
194 (sw1 == 0x90 && sw2 != 0x00)) {
195 memset(&error, 0, sizeof(error));
197 error.type = OFONO_ERROR_TYPE_SIM;
198 error.error = (sw1 << 8) | sw2;
200 cb(&error, NULL, 0, cbd->data);
204 if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
205 CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
209 DBG("crsm_read_cb: %02x, %02x, %d", sw1, sw2, len);
211 cb(&error, response, len, cbd->data);
214 static void at_sim_read_binary(struct ofono_sim *sim, int fileid,
215 int start, int length,
216 ofono_sim_read_cb_t cb, void *data)
218 struct sim_data *sd = ofono_sim_get_data(sim);
219 struct cb_data *cbd = cb_data_new(cb, data);
225 snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
226 start >> 8, start & 0xff, length);
228 if (g_at_chat_send(sd->chat, buf, crsm_prefix,
229 at_crsm_read_cb, cbd, g_free) > 0)
235 CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
238 static void at_sim_read_record(struct ofono_sim *sim, int fileid,
239 int record, int length,
240 ofono_sim_read_cb_t cb, void *data)
242 struct sim_data *sd = ofono_sim_get_data(sim);
243 struct cb_data *cbd = cb_data_new(cb, data);
249 snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
252 if (g_at_chat_send(sd->chat, buf, crsm_prefix,
253 at_crsm_read_cb, cbd, g_free) > 0)
259 CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
262 static void at_crsm_update_cb(gboolean ok, GAtResult *result,
265 struct cb_data *cbd = user_data;
267 ofono_sim_write_cb_t cb = cbd->cb;
268 struct ofono_error error;
271 decode_at_error(&error, g_at_result_final_response(result));
274 cb(&error, cbd->data);
278 g_at_result_iter_init(&iter, result);
280 if (!g_at_result_iter_next(&iter, "+CRSM:")) {
281 CALLBACK_WITH_FAILURE(cb, cbd->data);
285 g_at_result_iter_next_number(&iter, &sw1);
286 g_at_result_iter_next_number(&iter, &sw2);
288 if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
289 (sw1 == 0x90 && sw2 != 0x00)) {
290 memset(&error, 0, sizeof(error));
292 error.type = OFONO_ERROR_TYPE_SIM;
293 error.error = (sw1 << 8) | sw2;
296 DBG("crsm_update_cb: %02x, %02x", sw1, sw2);
298 cb(&error, cbd->data);
301 static void at_sim_update_binary(struct ofono_sim *sim, int fileid,
302 int start, int length,
303 const unsigned char *value,
304 ofono_sim_write_cb_t cb, void *data)
306 struct sim_data *sd = ofono_sim_get_data(sim);
307 struct cb_data *cbd = cb_data_new(cb, data);
308 char *buf = g_try_new(char, 36 + length * 2);
311 if (cbd == NULL || buf == NULL)
314 len = sprintf(buf, "AT+CRSM=214,%i,%i,%i,%i,", fileid,
315 start >> 8, start & 0xff, length);
317 for (; length; length--)
318 len += sprintf(buf + len, "%02hhX", *value++);
320 ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
321 at_crsm_update_cb, cbd, g_free);
331 CALLBACK_WITH_FAILURE(cb, data);
334 static void at_sim_update_record(struct ofono_sim *sim, int fileid,
335 int record, int length,
336 const unsigned char *value,
337 ofono_sim_write_cb_t cb, void *data)
339 struct sim_data *sd = ofono_sim_get_data(sim);
340 struct cb_data *cbd = cb_data_new(cb, data);
341 char *buf = g_try_new(char, 36 + length * 2);
344 if (cbd == NULL || buf == NULL)
347 len = sprintf(buf, "AT+CRSM=220,%i,%i,4,%i,", fileid,
350 for (; length; length--)
351 len += sprintf(buf + len, "%02hhX", *value++);
353 ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
354 at_crsm_update_cb, cbd, g_free);
364 CALLBACK_WITH_FAILURE(cb, data);
367 static void at_sim_update_cyclic(struct ofono_sim *sim, int fileid,
368 int length, const unsigned char *value,
369 ofono_sim_write_cb_t cb, void *data)
371 struct sim_data *sd = ofono_sim_get_data(sim);
372 struct cb_data *cbd = cb_data_new(cb, data);
373 char *buf = g_try_new(char, 36 + length * 2);
376 if (cbd == NULL || buf == NULL)
379 len = sprintf(buf, "AT+CRSM=220,%i,0,3,%i,", fileid, length);
381 for (; length; length--)
382 len += sprintf(buf + len, "%02hhX", *value++);
384 ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
385 at_crsm_update_cb, cbd, g_free);
395 CALLBACK_WITH_FAILURE(cb, data);
398 static void at_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data)
400 struct cb_data *cbd = user_data;
402 ofono_sim_imsi_cb_t cb = cbd->cb;
403 struct ofono_error error;
407 decode_at_error(&error, g_at_result_final_response(result));
410 cb(&error, NULL, cbd->data);
414 g_at_result_iter_init(&iter, result);
416 for (i = 0; i < g_at_result_num_response_lines(result); i++)
417 g_at_result_iter_next(&iter, NULL);
419 imsi = g_at_result_iter_raw_line(&iter);
421 DBG("cimi_cb: %s", imsi);
423 cb(&error, imsi, cbd->data);
426 static void at_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
429 struct sim_data *sd = ofono_sim_get_data(sim);
430 struct cb_data *cbd = cb_data_new(cb, data);
435 if (g_at_chat_send(sd->chat, "AT+CIMI", NULL,
436 at_cimi_cb, cbd, g_free) > 0)
442 CALLBACK_WITH_FAILURE(cb, NULL, data);
446 enum ofono_sim_password_type type;
448 } const at_sim_name[] = {
449 { OFONO_SIM_PASSWORD_NONE, "READY" },
450 { OFONO_SIM_PASSWORD_SIM_PIN, "SIM PIN" },
451 { OFONO_SIM_PASSWORD_SIM_PUK, "SIM PUK" },
452 { OFONO_SIM_PASSWORD_PHSIM_PIN, "PH-SIM PIN" },
453 { OFONO_SIM_PASSWORD_PHFSIM_PIN, "PH-FSIM PIN" },
454 { OFONO_SIM_PASSWORD_PHFSIM_PUK, "PH-FSIM PUK" },
455 { OFONO_SIM_PASSWORD_SIM_PIN2, "SIM PIN2" },
456 { OFONO_SIM_PASSWORD_SIM_PUK2, "SIM PUK2" },
457 { OFONO_SIM_PASSWORD_PHNET_PIN, "PH-NET PIN" },
458 { OFONO_SIM_PASSWORD_PHNET_PUK, "PH-NET PUK" },
459 { OFONO_SIM_PASSWORD_PHNETSUB_PIN, "PH-NETSUB PIN" },
460 { OFONO_SIM_PASSWORD_PHNETSUB_PUK, "PH-NETSUB PUK" },
461 { OFONO_SIM_PASSWORD_PHSP_PIN, "PH-SP PIN" },
462 { OFONO_SIM_PASSWORD_PHSP_PUK, "PH-SP PUK" },
463 { OFONO_SIM_PASSWORD_PHCORP_PIN, "PH-CORP PIN" },
464 { OFONO_SIM_PASSWORD_PHCORP_PUK, "PH-CORP PUK" },
467 #define BUILD_PIN_RETRIES_ARRAY(passwd_types, passwd_types_cnt, retry) \
468 for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++) \
471 for (i = 0; i < passwd_types_cnt; i++) { \
474 if (!g_at_result_iter_next_number(&iter, &val)) \
477 retry[passwd_types[i]] = val; \
479 DBG("retry counter id=%d, val=%d", passwd_types[i], \
480 retry[passwd_types[i]]); \
483 static void huawei_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
485 struct cb_data *cbd = user_data;
486 ofono_sim_pin_retries_cb_t cb = cbd->cb;
487 const char *final = g_at_result_final_response(result);
489 struct ofono_error error;
490 int retries[OFONO_SIM_PASSWORD_INVALID];
492 static enum ofono_sim_password_type password_types[] = {
493 OFONO_SIM_PASSWORD_SIM_PUK,
494 OFONO_SIM_PASSWORD_SIM_PIN,
495 OFONO_SIM_PASSWORD_SIM_PUK2,
496 OFONO_SIM_PASSWORD_SIM_PIN2,
499 decode_at_error(&error, final);
502 cb(&error, NULL, cbd->data);
506 g_at_result_iter_init(&iter, result);
508 if (!g_at_result_iter_next(&iter, "^CPIN:"))
511 /* Skip status since we are not interested in this */
512 if (!g_at_result_iter_skip_next(&iter))
515 /* Skip "overall counter" since we'll grab each one individually */
516 if (!g_at_result_iter_skip_next(&iter))
519 BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
522 cb(&error, retries, cbd->data);
527 CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
530 static void xpincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
532 struct cb_data *cbd = user_data;
533 ofono_sim_pin_retries_cb_t cb = cbd->cb;
534 const char *final = g_at_result_final_response(result);
536 struct ofono_error error;
537 int retries[OFONO_SIM_PASSWORD_INVALID];
539 static enum ofono_sim_password_type password_types[] = {
540 OFONO_SIM_PASSWORD_SIM_PIN,
541 OFONO_SIM_PASSWORD_SIM_PIN2,
542 OFONO_SIM_PASSWORD_SIM_PUK,
543 OFONO_SIM_PASSWORD_SIM_PUK2,
546 decode_at_error(&error, final);
549 cb(&error, NULL, cbd->data);
553 g_at_result_iter_init(&iter, result);
555 if (!g_at_result_iter_next(&iter, "+XPINCNT:"))
558 BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
561 cb(&error, retries, cbd->data);
566 CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
569 static void at_pin_retries_query(struct ofono_sim *sim,
570 ofono_sim_pin_retries_cb_t cb,
573 struct sim_data *sd = ofono_sim_get_data(sim);
574 struct cb_data *cbd = cb_data_new(cb, data);
581 switch (sd->vendor) {
582 case OFONO_VENDOR_IFX:
583 if (g_at_chat_send(sd->chat, "AT+XPINCNT", xpincnt_prefix,
584 xpincnt_cb, cbd, g_free) > 0)
588 case OFONO_VENDOR_HUAWEI:
589 if (g_at_chat_send(sd->chat, "AT^CPIN?", huawei_cpin_prefix,
590 huawei_cpin_cb, cbd, g_free) > 0)
600 CALLBACK_WITH_FAILURE(cb, NULL, data);
603 static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
605 struct cb_data *cbd = user_data;
606 struct sim_data *sd = ofono_sim_get_data(cbd->user);
608 ofono_sim_passwd_cb_t cb = cbd->cb;
609 struct ofono_error error;
610 const char *pin_required;
611 int pin_type = OFONO_SIM_PASSWORD_INVALID;
613 int len = sizeof(at_sim_name) / sizeof(*at_sim_name);
614 const char *final = g_at_result_final_response(result);
616 if (sd->vendor == OFONO_VENDOR_WAVECOM && ok && strlen(final) > 7)
617 decode_at_error(&error, "OK");
619 decode_at_error(&error, final);
622 cb(&error, -1, cbd->data);
626 if (sd->vendor == OFONO_VENDOR_WAVECOM) {
628 pin_required = final + 7;
630 g_at_result_iter_init(&iter, result);
632 if (!g_at_result_iter_next(&iter, "+CPIN:")) {
633 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
637 g_at_result_iter_next_unquoted_string(&iter, &pin_required);
640 for (i = 0; i < len; i++) {
641 if (strcmp(pin_required, at_sim_name[i].name))
644 pin_type = at_sim_name[i].type;
648 if (pin_type == OFONO_SIM_PASSWORD_INVALID) {
649 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
653 DBG("crsm_pin_cb: %s", pin_required);
655 cb(&error, pin_type, cbd->data);
658 static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
661 struct sim_data *sd = ofono_sim_get_data(sim);
662 struct cb_data *cbd = cb_data_new(cb, data);
669 if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
670 at_cpin_cb, cbd, g_free) > 0)
676 CALLBACK_WITH_FAILURE(cb, -1, data);
679 static void at_xsim_notify(GAtResult *result, gpointer user_data)
681 struct cb_data *cbd = user_data;
682 struct sim_data *sd = cbd->user;
683 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
684 struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
688 g_at_result_iter_init(&iter, result);
690 if (!g_at_result_iter_next(&iter, "+XSIM:"))
693 if (!g_at_result_iter_next_number(&iter, &state))
697 case 3: /* PIN verified – Ready */
698 case 7: /* ready for attach (+COPS) */
704 cb(&error, cbd->data);
706 g_at_chat_unregister(sd->chat, sd->ready_id);
710 static void at_epev_notify(GAtResult *result, gpointer user_data)
712 struct cb_data *cbd = user_data;
713 struct sim_data *sd = cbd->user;
714 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
715 struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
717 cb(&error, cbd->data);
719 g_at_chat_unregister(sd->chat, sd->ready_id);
723 static void at_pin_send_cb(gboolean ok, GAtResult *result,
726 struct cb_data *cbd = user_data;
727 struct sim_data *sd = cbd->user;
728 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
729 struct ofono_error error;
731 decode_at_error(&error, g_at_result_final_response(result));
736 switch (sd->vendor) {
737 case OFONO_VENDOR_IFX:
739 * On the IFX modem, AT+CPIN? can return READY too
740 * early and so use +XSIM notification to detect
741 * the ready state of the SIM.
743 sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
747 case OFONO_VENDOR_MBM:
749 * On the MBM modem, AT+CPIN? keeps returning SIM PIN
750 * for a moment after successful AT+CPIN="..", but then
751 * sends *EPEV when that changes.
753 sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
760 cb(&error, cbd->data);
765 static void at_pin_send(struct ofono_sim *sim, const char *passwd,
766 ofono_sim_lock_unlock_cb_t cb, void *data)
768 struct sim_data *sd = ofono_sim_get_data(sim);
769 struct cb_data *cbd = cb_data_new(cb, data);
778 snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
780 ret = g_at_chat_send(sd->chat, buf, none_prefix,
781 at_pin_send_cb, cbd, NULL);
783 memset(buf, 0, sizeof(buf));
791 CALLBACK_WITH_FAILURE(cb, data);
794 static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
796 ofono_sim_lock_unlock_cb_t cb, void *data)
798 struct sim_data *sd = ofono_sim_get_data(sim);
799 struct cb_data *cbd = cb_data_new(cb, data);
808 snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
810 ret = g_at_chat_send(sd->chat, buf, none_prefix,
811 at_pin_send_cb, cbd, NULL);
813 memset(buf, 0, sizeof(buf));
821 CALLBACK_WITH_FAILURE(cb, data);
824 static void at_lock_unlock_cb(gboolean ok, GAtResult *result,
827 struct cb_data *cbd = user_data;
828 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
829 struct ofono_error error;
831 decode_at_error(&error, g_at_result_final_response(result));
833 cb(&error, cbd->data);
836 static const char *const at_clck_cpwd_fac[] = {
837 [OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
838 [OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
839 [OFONO_SIM_PASSWORD_PHSIM_PIN] = "PS",
840 [OFONO_SIM_PASSWORD_PHFSIM_PIN] = "PF",
841 [OFONO_SIM_PASSWORD_PHNET_PIN] = "PN",
842 [OFONO_SIM_PASSWORD_PHNETSUB_PIN] = "PU",
843 [OFONO_SIM_PASSWORD_PHSP_PIN] = "PP",
844 [OFONO_SIM_PASSWORD_PHCORP_PIN] = "PC",
847 static void at_pin_enable(struct ofono_sim *sim,
848 enum ofono_sim_password_type passwd_type,
849 int enable, const char *passwd,
850 ofono_sim_lock_unlock_cb_t cb, void *data)
852 struct sim_data *sd = ofono_sim_get_data(sim);
853 struct cb_data *cbd = cb_data_new(cb, data);
856 unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
861 if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
864 snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
865 at_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd);
867 ret = g_at_chat_send(sd->chat, buf, none_prefix,
868 at_lock_unlock_cb, cbd, g_free);
870 memset(buf, 0, sizeof(buf));
878 CALLBACK_WITH_FAILURE(cb, data);
881 static void at_change_passwd(struct ofono_sim *sim,
882 enum ofono_sim_password_type passwd_type,
883 const char *old, const char *new,
884 ofono_sim_lock_unlock_cb_t cb, void *data)
886 struct sim_data *sd = ofono_sim_get_data(sim);
887 struct cb_data *cbd = cb_data_new(cb, data);
890 unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
895 if (passwd_type >= len ||
896 at_clck_cpwd_fac[passwd_type] == NULL)
899 snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
900 at_clck_cpwd_fac[passwd_type], old, new);
902 ret = g_at_chat_send(sd->chat, buf, none_prefix,
903 at_lock_unlock_cb, cbd, g_free);
905 memset(buf, 0, sizeof(buf));
913 CALLBACK_WITH_FAILURE(cb, data);
916 static void at_lock_status_cb(gboolean ok, GAtResult *result,
919 struct cb_data *cbd = user_data;
921 ofono_sim_locked_cb_t cb = cbd->cb;
922 struct ofono_error error;
925 decode_at_error(&error, g_at_result_final_response(result));
928 cb(&error, -1, cbd->data);
932 g_at_result_iter_init(&iter, result);
934 if (!g_at_result_iter_next(&iter, "+CLCK:")) {
935 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
939 g_at_result_iter_next_number(&iter, &locked);
941 DBG("lock_status_cb: %i", locked);
943 cb(&error, locked, cbd->data);
946 static void at_pin_query_enabled(struct ofono_sim *sim,
947 enum ofono_sim_password_type passwd_type,
948 ofono_sim_locked_cb_t cb, void *data)
950 struct sim_data *sd = ofono_sim_get_data(sim);
951 struct cb_data *cbd = cb_data_new(cb, data);
953 unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
958 if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
961 snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
962 at_clck_cpwd_fac[passwd_type]);
964 if (g_at_chat_send(sd->chat, buf, clck_prefix,
965 at_lock_status_cb, cbd, g_free) > 0)
971 CALLBACK_WITH_FAILURE(cb, -1, data);
974 static gboolean at_sim_register(gpointer user)
976 struct ofono_sim *sim = user;
978 ofono_sim_register(sim);
983 static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
986 GAtChat *chat = data;
989 sd = g_new0(struct sim_data, 1);
990 sd->chat = g_at_chat_clone(chat);
993 switch (sd->vendor) {
994 case OFONO_VENDOR_WAVECOM:
995 g_at_chat_add_terminator(sd->chat, "+CPIN:", 6, TRUE);
997 case OFONO_VENDOR_MBM:
998 g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
1004 ofono_sim_set_data(sim, sd);
1005 g_idle_add(at_sim_register, sim);
1010 static void at_sim_remove(struct ofono_sim *sim)
1012 struct sim_data *sd = ofono_sim_get_data(sim);
1014 ofono_sim_set_data(sim, NULL);
1016 g_at_chat_unref(sd->chat);
1020 static struct ofono_sim_driver driver = {
1022 .probe = at_sim_probe,
1023 .remove = at_sim_remove,
1024 .read_file_info = at_sim_read_info,
1025 .read_file_transparent = at_sim_read_binary,
1026 .read_file_linear = at_sim_read_record,
1027 .read_file_cyclic = at_sim_read_record,
1028 .write_file_transparent = at_sim_update_binary,
1029 .write_file_linear = at_sim_update_record,
1030 .write_file_cyclic = at_sim_update_cyclic,
1031 .read_imsi = at_read_imsi,
1032 .query_passwd_state = at_pin_query,
1033 .query_pin_retries = at_pin_retries_query,
1034 .send_passwd = at_pin_send,
1035 .reset_passwd = at_pin_send_puk,
1036 .lock = at_pin_enable,
1037 .change_passwd = at_change_passwd,
1038 .query_locked = at_pin_query_enabled,
1041 void at_sim_init(void)
1043 ofono_sim_driver_register(&driver);
1046 void at_sim_exit(void)
1048 ofono_sim_driver_unregister(&driver);