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 *cpinr_prefixes[] = { "+CPINR:", "+CPINRE:", NULL };
61 static const char *none_prefix[] = { NULL };
63 static void at_crsm_info_cb(gboolean ok, GAtResult *result, gpointer user_data)
65 struct cb_data *cbd = user_data;
67 ofono_sim_file_info_cb_t cb = cbd->cb;
68 struct ofono_error error;
69 const guint8 *response;
73 unsigned char access[3];
74 unsigned char file_status;
76 decode_at_error(&error, g_at_result_final_response(result));
79 cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
83 g_at_result_iter_init(&iter, result);
85 if (!g_at_result_iter_next(&iter, "+CRSM:"))
88 g_at_result_iter_next_number(&iter, &sw1);
89 g_at_result_iter_next_number(&iter, &sw2);
91 if (!g_at_result_iter_next_hexstring(&iter, &response, &len) ||
92 (sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92) ||
93 (sw1 == 0x90 && sw2 != 0x00)) {
94 memset(&error, 0, sizeof(error));
96 error.type = OFONO_ERROR_TYPE_SIM;
97 error.error = (sw1 << 8) | sw2;
99 cb(&error, -1, -1, -1, NULL, EF_STATUS_INVALIDATED, cbd->data);
103 DBG("crsm_info_cb: %02x, %02x, %i", sw1, sw2, len);
105 if (response[0] == 0x62) {
106 ok = sim_parse_3g_get_response(response, len, &flen, &rlen,
109 file_status = EF_STATUS_VALID;
112 ok = sim_parse_2g_get_response(response, len, &flen, &rlen,
113 &str, access, &file_status);
118 cb(&error, flen, str, rlen, access, file_status, cbd->data);
123 CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
124 EF_STATUS_INVALIDATED, cbd->data);
127 static void at_sim_read_info(struct ofono_sim *sim, int fileid,
128 ofono_sim_file_info_cb_t cb,
131 struct sim_data *sd = ofono_sim_get_data(sim);
135 if (sd->vendor == OFONO_VENDOR_OPTION_HSO) {
136 unsigned char access[3] = { 0x00, 0x00, 0x00 };
138 if (fileid == SIM_EFAD_FILEID) {
139 CALLBACK_WITH_SUCCESS(cb, 4, 0, 0, access,
140 EF_STATUS_VALID, data);
145 cbd = cb_data_new(cb, data);
147 snprintf(buf, sizeof(buf), "AT+CRSM=192,%i", fileid);
149 switch (sd->vendor) {
150 case OFONO_VENDOR_HUAWEI:
151 case OFONO_VENDOR_SIERRA:
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)
163 CALLBACK_WITH_FAILURE(cb, -1, -1, -1, NULL,
164 EF_STATUS_INVALIDATED, data);
167 static void at_crsm_read_cb(gboolean ok, GAtResult *result,
170 struct cb_data *cbd = user_data;
172 ofono_sim_read_cb_t cb = cbd->cb;
173 struct ofono_error error;
174 const guint8 *response;
177 decode_at_error(&error, g_at_result_final_response(result));
180 cb(&error, NULL, 0, cbd->data);
184 g_at_result_iter_init(&iter, result);
186 if (!g_at_result_iter_next(&iter, "+CRSM:")) {
187 CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
191 g_at_result_iter_next_number(&iter, &sw1);
192 g_at_result_iter_next_number(&iter, &sw2);
194 if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
195 (sw1 == 0x90 && sw2 != 0x00)) {
196 memset(&error, 0, sizeof(error));
198 error.type = OFONO_ERROR_TYPE_SIM;
199 error.error = (sw1 << 8) | sw2;
201 cb(&error, NULL, 0, cbd->data);
205 if (!g_at_result_iter_next_hexstring(&iter, &response, &len)) {
206 CALLBACK_WITH_FAILURE(cb, NULL, 0, cbd->data);
210 DBG("crsm_read_cb: %02x, %02x, %d", sw1, sw2, len);
212 cb(&error, response, len, cbd->data);
215 static void at_sim_read_binary(struct ofono_sim *sim, int fileid,
216 int start, int length,
217 ofono_sim_read_cb_t cb, void *data)
219 struct sim_data *sd = ofono_sim_get_data(sim);
220 struct cb_data *cbd = cb_data_new(cb, data);
223 snprintf(buf, sizeof(buf), "AT+CRSM=176,%i,%i,%i,%i", fileid,
224 start >> 8, start & 0xff, length);
226 if (g_at_chat_send(sd->chat, buf, crsm_prefix,
227 at_crsm_read_cb, cbd, g_free) > 0)
232 CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
235 static void at_sim_read_record(struct ofono_sim *sim, int fileid,
236 int record, int length,
237 ofono_sim_read_cb_t cb, void *data)
239 struct sim_data *sd = ofono_sim_get_data(sim);
240 struct cb_data *cbd = cb_data_new(cb, data);
243 snprintf(buf, sizeof(buf), "AT+CRSM=178,%i,%i,4,%i", fileid,
246 if (g_at_chat_send(sd->chat, buf, crsm_prefix,
247 at_crsm_read_cb, cbd, g_free) > 0)
252 CALLBACK_WITH_FAILURE(cb, NULL, 0, data);
255 static void at_crsm_update_cb(gboolean ok, GAtResult *result,
258 struct cb_data *cbd = user_data;
260 ofono_sim_write_cb_t cb = cbd->cb;
261 struct ofono_error error;
264 decode_at_error(&error, g_at_result_final_response(result));
267 cb(&error, cbd->data);
271 g_at_result_iter_init(&iter, result);
273 if (!g_at_result_iter_next(&iter, "+CRSM:")) {
274 CALLBACK_WITH_FAILURE(cb, cbd->data);
278 g_at_result_iter_next_number(&iter, &sw1);
279 g_at_result_iter_next_number(&iter, &sw2);
281 if ((sw1 != 0x90 && sw1 != 0x91 && sw1 != 0x92 && sw1 != 0x9f) ||
282 (sw1 == 0x90 && sw2 != 0x00)) {
283 memset(&error, 0, sizeof(error));
285 error.type = OFONO_ERROR_TYPE_SIM;
286 error.error = (sw1 << 8) | sw2;
289 DBG("crsm_update_cb: %02x, %02x", sw1, sw2);
291 cb(&error, cbd->data);
294 static void at_sim_update_binary(struct ofono_sim *sim, int fileid,
295 int start, int length,
296 const unsigned char *value,
297 ofono_sim_write_cb_t cb, void *data)
299 struct sim_data *sd = ofono_sim_get_data(sim);
300 struct cb_data *cbd = cb_data_new(cb, data);
301 char *buf = g_try_new(char, 36 + length * 2);
307 len = sprintf(buf, "AT+CRSM=214,%i,%i,%i,%i,", fileid,
308 start >> 8, start & 0xff, length);
310 for (; length; length--)
311 len += sprintf(buf + len, "%02hhX", *value++);
313 ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
314 at_crsm_update_cb, cbd, g_free);
324 CALLBACK_WITH_FAILURE(cb, data);
327 static void at_sim_update_record(struct ofono_sim *sim, int fileid,
328 int record, int length,
329 const unsigned char *value,
330 ofono_sim_write_cb_t cb, void *data)
332 struct sim_data *sd = ofono_sim_get_data(sim);
333 struct cb_data *cbd = cb_data_new(cb, data);
334 char *buf = g_try_new(char, 36 + length * 2);
340 len = sprintf(buf, "AT+CRSM=220,%i,%i,4,%i,", fileid,
343 for (; length; length--)
344 len += sprintf(buf + len, "%02hhX", *value++);
346 ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
347 at_crsm_update_cb, cbd, g_free);
357 CALLBACK_WITH_FAILURE(cb, data);
360 static void at_sim_update_cyclic(struct ofono_sim *sim, int fileid,
361 int length, const unsigned char *value,
362 ofono_sim_write_cb_t cb, void *data)
364 struct sim_data *sd = ofono_sim_get_data(sim);
365 struct cb_data *cbd = cb_data_new(cb, data);
366 char *buf = g_try_new(char, 36 + length * 2);
372 len = sprintf(buf, "AT+CRSM=220,%i,0,3,%i,", fileid, length);
374 for (; length; length--)
375 len += sprintf(buf + len, "%02hhX", *value++);
377 ret = g_at_chat_send(sd->chat, buf, crsm_prefix,
378 at_crsm_update_cb, cbd, g_free);
388 CALLBACK_WITH_FAILURE(cb, data);
391 static void at_cimi_cb(gboolean ok, GAtResult *result, gpointer user_data)
393 struct cb_data *cbd = user_data;
395 ofono_sim_imsi_cb_t cb = cbd->cb;
396 struct ofono_error error;
400 decode_at_error(&error, g_at_result_final_response(result));
403 cb(&error, NULL, cbd->data);
407 g_at_result_iter_init(&iter, result);
409 for (i = 0; i < g_at_result_num_response_lines(result); i++)
410 g_at_result_iter_next(&iter, NULL);
412 imsi = g_at_result_iter_raw_line(&iter);
414 DBG("cimi_cb: %s", imsi);
416 cb(&error, imsi, cbd->data);
419 static void at_read_imsi(struct ofono_sim *sim, ofono_sim_imsi_cb_t cb,
422 struct sim_data *sd = ofono_sim_get_data(sim);
423 struct cb_data *cbd = cb_data_new(cb, data);
425 if (g_at_chat_send(sd->chat, "AT+CIMI", NULL,
426 at_cimi_cb, cbd, g_free) > 0)
431 CALLBACK_WITH_FAILURE(cb, NULL, data);
435 enum ofono_sim_password_type type;
437 } const at_sim_name[] = {
438 { OFONO_SIM_PASSWORD_NONE, "READY" },
439 { OFONO_SIM_PASSWORD_SIM_PIN, "SIM PIN" },
440 { OFONO_SIM_PASSWORD_SIM_PUK, "SIM PUK" },
441 { OFONO_SIM_PASSWORD_PHSIM_PIN, "PH-SIM PIN" },
442 { OFONO_SIM_PASSWORD_PHFSIM_PIN, "PH-FSIM PIN" },
443 { OFONO_SIM_PASSWORD_PHFSIM_PUK, "PH-FSIM PUK" },
444 { OFONO_SIM_PASSWORD_SIM_PIN2, "SIM PIN2" },
445 { OFONO_SIM_PASSWORD_SIM_PUK2, "SIM PUK2" },
446 { OFONO_SIM_PASSWORD_PHNET_PIN, "PH-NET PIN" },
447 { OFONO_SIM_PASSWORD_PHNET_PUK, "PH-NET PUK" },
448 { OFONO_SIM_PASSWORD_PHNETSUB_PIN, "PH-NETSUB PIN" },
449 { OFONO_SIM_PASSWORD_PHNETSUB_PUK, "PH-NETSUB PUK" },
450 { OFONO_SIM_PASSWORD_PHSP_PIN, "PH-SP PIN" },
451 { OFONO_SIM_PASSWORD_PHSP_PUK, "PH-SP PUK" },
452 { OFONO_SIM_PASSWORD_PHCORP_PIN, "PH-CORP PIN" },
453 { OFONO_SIM_PASSWORD_PHCORP_PUK, "PH-CORP PUK" },
456 #define BUILD_PIN_RETRIES_ARRAY(passwd_types, passwd_types_cnt, retry) \
457 for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++) \
460 for (i = 0; i < passwd_types_cnt; i++) { \
463 if (!g_at_result_iter_next_number(&iter, &val)) \
466 retry[passwd_types[i]] = val; \
468 DBG("retry counter id=%d, val=%d", passwd_types[i], \
469 retry[passwd_types[i]]); \
472 static void huawei_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
474 struct cb_data *cbd = user_data;
475 ofono_sim_pin_retries_cb_t cb = cbd->cb;
476 const char *final = g_at_result_final_response(result);
478 struct ofono_error error;
479 int retries[OFONO_SIM_PASSWORD_INVALID];
481 static enum ofono_sim_password_type password_types[] = {
482 OFONO_SIM_PASSWORD_SIM_PUK,
483 OFONO_SIM_PASSWORD_SIM_PIN,
484 OFONO_SIM_PASSWORD_SIM_PUK2,
485 OFONO_SIM_PASSWORD_SIM_PIN2,
488 decode_at_error(&error, final);
491 cb(&error, NULL, cbd->data);
495 g_at_result_iter_init(&iter, result);
497 if (!g_at_result_iter_next(&iter, "^CPIN:"))
500 /* Skip status since we are not interested in this */
501 if (!g_at_result_iter_skip_next(&iter))
504 /* Skip "overall counter" since we'll grab each one individually */
505 if (!g_at_result_iter_skip_next(&iter))
508 BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
511 cb(&error, retries, cbd->data);
516 CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
519 static void xpincnt_cb(gboolean ok, GAtResult *result, gpointer user_data)
521 struct cb_data *cbd = user_data;
522 ofono_sim_pin_retries_cb_t cb = cbd->cb;
523 const char *final = g_at_result_final_response(result);
525 struct ofono_error error;
526 int retries[OFONO_SIM_PASSWORD_INVALID];
528 static enum ofono_sim_password_type password_types[] = {
529 OFONO_SIM_PASSWORD_SIM_PIN,
530 OFONO_SIM_PASSWORD_SIM_PIN2,
531 OFONO_SIM_PASSWORD_SIM_PUK,
532 OFONO_SIM_PASSWORD_SIM_PUK2,
535 decode_at_error(&error, final);
538 cb(&error, NULL, cbd->data);
542 g_at_result_iter_init(&iter, result);
544 if (!g_at_result_iter_next(&iter, "+XPINCNT:"))
547 BUILD_PIN_RETRIES_ARRAY(password_types, ARRAY_SIZE(password_types),
550 cb(&error, retries, cbd->data);
555 CALLBACK_WITH_FAILURE(cb, NULL, cbd->data);
558 static void at_cpinr_cb(gboolean ok, GAtResult *result, gpointer user_data)
560 struct cb_data *cbd = user_data;
561 ofono_sim_pin_retries_cb_t cb = cbd->cb;
563 struct ofono_error error;
564 int retries[OFONO_SIM_PASSWORD_INVALID];
565 size_t len = sizeof(at_sim_name) / sizeof(*at_sim_name);
568 decode_at_error(&error, g_at_result_final_response(result));
571 cb(&error, NULL, cbd->data);
575 for (i = 0; i < OFONO_SIM_PASSWORD_INVALID; i++)
578 g_at_result_iter_init(&iter, result);
580 /* Ignore +CPINRE results... */
581 while (g_at_result_iter_next(&iter, "+CPINR:")) {
585 if (!g_at_result_iter_next_unquoted_string(&iter, &name))
588 if (!g_at_result_iter_next_number(&iter, &val))
591 for (i = 1; i < len; i++) {
592 if (!strcmp(name, at_sim_name[i].name)) {
599 cb(&error, retries, cbd->data);
602 static void at_pin_retries_query(struct ofono_sim *sim,
603 ofono_sim_pin_retries_cb_t cb,
606 struct sim_data *sd = ofono_sim_get_data(sim);
607 struct cb_data *cbd = cb_data_new(cb, data);
611 switch (sd->vendor) {
612 case OFONO_VENDOR_IFX:
613 if (g_at_chat_send(sd->chat, "AT+XPINCNT", xpincnt_prefix,
614 xpincnt_cb, cbd, g_free) > 0)
618 case OFONO_VENDOR_HUAWEI:
619 if (g_at_chat_send(sd->chat, "AT^CPIN?", huawei_cpin_prefix,
620 huawei_cpin_cb, cbd, g_free) > 0)
625 if (g_at_chat_send(sd->chat, "AT+CPINR", cpinr_prefixes,
626 at_cpinr_cb, cbd, g_free) > 0)
633 CALLBACK_WITH_FAILURE(cb, NULL, data);
636 static void at_cpin_cb(gboolean ok, GAtResult *result, gpointer user_data)
638 struct cb_data *cbd = user_data;
639 struct sim_data *sd = ofono_sim_get_data(cbd->user);
641 ofono_sim_passwd_cb_t cb = cbd->cb;
642 struct ofono_error error;
643 const char *pin_required;
644 int pin_type = OFONO_SIM_PASSWORD_INVALID;
646 int len = sizeof(at_sim_name) / sizeof(*at_sim_name);
647 const char *final = g_at_result_final_response(result);
649 if (sd->vendor == OFONO_VENDOR_WAVECOM && ok && strlen(final) > 7)
650 decode_at_error(&error, "OK");
652 decode_at_error(&error, final);
655 cb(&error, -1, cbd->data);
659 if (sd->vendor == OFONO_VENDOR_WAVECOM) {
661 pin_required = final + 7;
663 g_at_result_iter_init(&iter, result);
665 if (!g_at_result_iter_next(&iter, "+CPIN:")) {
666 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
670 g_at_result_iter_next_unquoted_string(&iter, &pin_required);
673 for (i = 0; i < len; i++) {
674 if (strcmp(pin_required, at_sim_name[i].name))
677 pin_type = at_sim_name[i].type;
681 if (pin_type == OFONO_SIM_PASSWORD_INVALID) {
682 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
686 DBG("crsm_pin_cb: %s", pin_required);
688 cb(&error, pin_type, cbd->data);
691 static void at_pin_query(struct ofono_sim *sim, ofono_sim_passwd_cb_t cb,
694 struct sim_data *sd = ofono_sim_get_data(sim);
695 struct cb_data *cbd = cb_data_new(cb, data);
699 if (g_at_chat_send(sd->chat, "AT+CPIN?", cpin_prefix,
700 at_cpin_cb, cbd, g_free) > 0)
705 CALLBACK_WITH_FAILURE(cb, -1, data);
708 static void at_xsim_notify(GAtResult *result, gpointer user_data)
710 struct cb_data *cbd = user_data;
711 struct sim_data *sd = cbd->user;
712 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
713 struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
717 g_at_result_iter_init(&iter, result);
719 if (!g_at_result_iter_next(&iter, "+XSIM:"))
722 if (!g_at_result_iter_next_number(&iter, &state))
726 case 3: /* PIN verified – Ready */
727 case 7: /* ready for attach (+COPS) */
733 cb(&error, cbd->data);
735 g_at_chat_unregister(sd->chat, sd->ready_id);
739 static void at_epev_notify(GAtResult *result, gpointer user_data)
741 struct cb_data *cbd = user_data;
742 struct sim_data *sd = cbd->user;
743 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
744 struct ofono_error error = { .type = OFONO_ERROR_TYPE_NO_ERROR };
746 cb(&error, cbd->data);
748 g_at_chat_unregister(sd->chat, sd->ready_id);
752 static void at_pin_send_cb(gboolean ok, GAtResult *result,
755 struct cb_data *cbd = user_data;
756 struct sim_data *sd = cbd->user;
757 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
758 struct ofono_error error;
760 decode_at_error(&error, g_at_result_final_response(result));
765 switch (sd->vendor) {
766 case OFONO_VENDOR_IFX:
768 * On the IFX modem, AT+CPIN? can return READY too
769 * early and so use +XSIM notification to detect
770 * the ready state of the SIM.
772 sd->ready_id = g_at_chat_register(sd->chat, "+XSIM",
776 case OFONO_VENDOR_MBM:
778 * On the MBM modem, AT+CPIN? keeps returning SIM PIN
779 * for a moment after successful AT+CPIN="..", but then
780 * sends *EPEV when that changes.
782 sd->ready_id = g_at_chat_register(sd->chat, "*EPEV",
789 cb(&error, cbd->data);
794 static void at_pin_send(struct ofono_sim *sim, const char *passwd,
795 ofono_sim_lock_unlock_cb_t cb, void *data)
797 struct sim_data *sd = ofono_sim_get_data(sim);
798 struct cb_data *cbd = cb_data_new(cb, data);
804 snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\"", passwd);
806 ret = g_at_chat_send(sd->chat, buf, none_prefix,
807 at_pin_send_cb, cbd, NULL);
809 memset(buf, 0, sizeof(buf));
816 CALLBACK_WITH_FAILURE(cb, data);
819 static void at_pin_send_puk(struct ofono_sim *sim, const char *puk,
821 ofono_sim_lock_unlock_cb_t cb, void *data)
823 struct sim_data *sd = ofono_sim_get_data(sim);
824 struct cb_data *cbd = cb_data_new(cb, data);
830 snprintf(buf, sizeof(buf), "AT+CPIN=\"%s\",\"%s\"", puk, passwd);
832 ret = g_at_chat_send(sd->chat, buf, none_prefix,
833 at_pin_send_cb, cbd, NULL);
835 memset(buf, 0, sizeof(buf));
842 CALLBACK_WITH_FAILURE(cb, data);
845 static void at_lock_unlock_cb(gboolean ok, GAtResult *result,
848 struct cb_data *cbd = user_data;
849 ofono_sim_lock_unlock_cb_t cb = cbd->cb;
850 struct ofono_error error;
852 decode_at_error(&error, g_at_result_final_response(result));
854 cb(&error, cbd->data);
857 static const char *const at_clck_cpwd_fac[] = {
858 [OFONO_SIM_PASSWORD_SIM_PIN] = "SC",
859 [OFONO_SIM_PASSWORD_SIM_PIN2] = "P2",
860 [OFONO_SIM_PASSWORD_PHSIM_PIN] = "PS",
861 [OFONO_SIM_PASSWORD_PHFSIM_PIN] = "PF",
862 [OFONO_SIM_PASSWORD_PHNET_PIN] = "PN",
863 [OFONO_SIM_PASSWORD_PHNETSUB_PIN] = "PU",
864 [OFONO_SIM_PASSWORD_PHSP_PIN] = "PP",
865 [OFONO_SIM_PASSWORD_PHCORP_PIN] = "PC",
868 static void at_pin_enable(struct ofono_sim *sim,
869 enum ofono_sim_password_type passwd_type,
870 int enable, const char *passwd,
871 ofono_sim_lock_unlock_cb_t cb, void *data)
873 struct sim_data *sd = ofono_sim_get_data(sim);
874 struct cb_data *cbd = cb_data_new(cb, data);
877 unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
879 if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
882 snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",%i,\"%s\"",
883 at_clck_cpwd_fac[passwd_type], enable ? 1 : 0, passwd);
885 ret = g_at_chat_send(sd->chat, buf, none_prefix,
886 at_lock_unlock_cb, cbd, g_free);
888 memset(buf, 0, sizeof(buf));
896 CALLBACK_WITH_FAILURE(cb, data);
899 static void at_change_passwd(struct ofono_sim *sim,
900 enum ofono_sim_password_type passwd_type,
901 const char *old_passwd, const char *new_passwd,
902 ofono_sim_lock_unlock_cb_t cb, void *data)
904 struct sim_data *sd = ofono_sim_get_data(sim);
905 struct cb_data *cbd = cb_data_new(cb, data);
908 unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
910 if (passwd_type >= len ||
911 at_clck_cpwd_fac[passwd_type] == NULL)
914 snprintf(buf, sizeof(buf), "AT+CPWD=\"%s\",\"%s\",\"%s\"",
915 at_clck_cpwd_fac[passwd_type], old_passwd, new_passwd);
917 ret = g_at_chat_send(sd->chat, buf, none_prefix,
918 at_lock_unlock_cb, cbd, g_free);
920 memset(buf, 0, sizeof(buf));
928 CALLBACK_WITH_FAILURE(cb, data);
931 static void at_lock_status_cb(gboolean ok, GAtResult *result,
934 struct cb_data *cbd = user_data;
936 ofono_sim_locked_cb_t cb = cbd->cb;
937 struct ofono_error error;
940 decode_at_error(&error, g_at_result_final_response(result));
943 cb(&error, -1, cbd->data);
947 g_at_result_iter_init(&iter, result);
949 if (!g_at_result_iter_next(&iter, "+CLCK:")) {
950 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
954 g_at_result_iter_next_number(&iter, &locked);
956 DBG("lock_status_cb: %i", locked);
958 cb(&error, locked, cbd->data);
961 static void at_pin_query_enabled(struct ofono_sim *sim,
962 enum ofono_sim_password_type passwd_type,
963 ofono_sim_locked_cb_t cb, void *data)
965 struct sim_data *sd = ofono_sim_get_data(sim);
966 struct cb_data *cbd = cb_data_new(cb, data);
968 unsigned int len = sizeof(at_clck_cpwd_fac) / sizeof(*at_clck_cpwd_fac);
970 if (passwd_type >= len || at_clck_cpwd_fac[passwd_type] == NULL)
973 snprintf(buf, sizeof(buf), "AT+CLCK=\"%s\",2",
974 at_clck_cpwd_fac[passwd_type]);
976 if (g_at_chat_send(sd->chat, buf, clck_prefix,
977 at_lock_status_cb, cbd, g_free) > 0)
983 CALLBACK_WITH_FAILURE(cb, -1, data);
986 static gboolean at_sim_register(gpointer user)
988 struct ofono_sim *sim = user;
990 ofono_sim_register(sim);
995 static int at_sim_probe(struct ofono_sim *sim, unsigned int vendor,
998 GAtChat *chat = data;
1001 sd = g_new0(struct sim_data, 1);
1002 sd->chat = g_at_chat_clone(chat);
1003 sd->vendor = vendor;
1005 switch (sd->vendor) {
1006 case OFONO_VENDOR_WAVECOM:
1007 g_at_chat_add_terminator(sd->chat, "+CPIN:", 6, TRUE);
1009 case OFONO_VENDOR_MBM:
1010 g_at_chat_send(sd->chat, "AT*EPEE=1", NULL, NULL, NULL, NULL);
1016 ofono_sim_set_data(sim, sd);
1017 g_idle_add(at_sim_register, sim);
1022 static void at_sim_remove(struct ofono_sim *sim)
1024 struct sim_data *sd = ofono_sim_get_data(sim);
1026 ofono_sim_set_data(sim, NULL);
1028 g_at_chat_unref(sd->chat);
1032 static struct ofono_sim_driver driver = {
1034 .probe = at_sim_probe,
1035 .remove = at_sim_remove,
1036 .read_file_info = at_sim_read_info,
1037 .read_file_transparent = at_sim_read_binary,
1038 .read_file_linear = at_sim_read_record,
1039 .read_file_cyclic = at_sim_read_record,
1040 .write_file_transparent = at_sim_update_binary,
1041 .write_file_linear = at_sim_update_record,
1042 .write_file_cyclic = at_sim_update_cyclic,
1043 .read_imsi = at_read_imsi,
1044 .query_passwd_state = at_pin_query,
1045 .query_pin_retries = at_pin_retries_query,
1046 .send_passwd = at_pin_send,
1047 .reset_passwd = at_pin_send_puk,
1048 .lock = at_pin_enable,
1049 .change_passwd = at_change_passwd,
1050 .query_locked = at_pin_query_enabled,
1053 void at_sim_init(void)
1055 ofono_sim_driver_register(&driver);
1058 void at_sim_exit(void)
1060 ofono_sim_driver_unregister(&driver);