/drivers/atmodem/sim-poll.c

https://github.com/Paulxia/ofono · C · 257 lines · 163 code · 62 blank · 32 comment · 34 complexity · eb2eb174be4e09a3150cadd15d5ba9a1 MD5 · raw file

  1. /*
  2. *
  3. * oFono - Open Source Telephony
  4. *
  5. * Copyright (C) 2008-2010 Intel Corporation. All rights reserved.
  6. *
  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.
  10. *
  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.
  15. *
  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
  19. *
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #define _GNU_SOURCE
  25. #include <stdio.h>
  26. #include <glib.h>
  27. #include <ofono/log.h>
  28. #include <ofono/modem.h>
  29. #include <ofono/sim.h>
  30. #include <ofono/stk.h>
  31. #include "gatchat.h"
  32. #include "gatresult.h"
  33. #include "ofono.h"
  34. #include "atmodem.h"
  35. #include "sim-poll.h"
  36. #include "stk.h"
  37. struct sim_poll_data {
  38. GAtChat *chat;
  39. struct ofono_modem *modem;
  40. struct ofono_sim *sim;
  41. struct ofono_stk *stk;
  42. unsigned int sim_watch;
  43. unsigned int stk_watch;
  44. unsigned int sim_state_watch;
  45. gboolean inserted;
  46. int idle_poll_interval;
  47. gint status_timeout;
  48. gint poll_timeout;
  49. guint status_cmd;
  50. };
  51. static const char *csim_prefix[] = { "+CSIM:", NULL };
  52. static gboolean sim_status_poll(gpointer user_data);
  53. static void sim_status_poll_schedule(struct sim_poll_data *spd)
  54. {
  55. /* TODO: Decide on the interval based on whether any call is active */
  56. /* TODO: On idle, possibly only schedule if proactive commands enabled
  57. * as indicated by EFphase + EFsst (51.011: 11.6.1) */
  58. int interval = spd->idle_poll_interval;
  59. /* When a SIM is inserted, the SIM might have requested a different
  60. * interval. */
  61. if (spd->inserted)
  62. interval = ofono_modem_get_integer(spd->modem,
  63. "status-poll-interval");
  64. spd->poll_timeout = g_timeout_add_seconds(interval,
  65. sim_status_poll, spd);
  66. }
  67. static gboolean sim_status_timeout(gpointer user_data)
  68. {
  69. struct sim_poll_data *spd = user_data;
  70. spd->status_timeout = 0;
  71. g_at_chat_cancel(spd->chat, spd->status_cmd);
  72. spd->status_cmd = 0;
  73. if (spd->inserted == TRUE) {
  74. spd->inserted = FALSE;
  75. ofono_sim_inserted_notify(spd->sim, FALSE);
  76. }
  77. sim_status_poll_schedule(spd);
  78. return FALSE;
  79. }
  80. static void at_csim_status_cb(gboolean ok, GAtResult *result,
  81. gpointer user_data)
  82. {
  83. struct sim_poll_data *spd = user_data;
  84. GAtResultIter iter;
  85. const guint8 *response;
  86. gint rlen, len;
  87. spd->status_cmd = 0;
  88. if (!spd->status_timeout)
  89. /* The STATUS already timed out */
  90. return;
  91. /* Card responded on time */
  92. g_source_remove(spd->status_timeout);
  93. spd->status_timeout = 0;
  94. if (spd->inserted != TRUE) {
  95. spd->inserted = TRUE;
  96. ofono_sim_inserted_notify(spd->sim, TRUE);
  97. }
  98. sim_status_poll_schedule(spd);
  99. /* Check if we have a proactive command */
  100. if (!ok)
  101. return;
  102. g_at_result_iter_init(&iter, result);
  103. if (!g_at_result_iter_next(&iter, "+CSIM:"))
  104. return;
  105. if (!g_at_result_iter_next_number(&iter, &rlen))
  106. return;
  107. if (!g_at_result_iter_next_hexstring(&iter, &response, &len))
  108. return;
  109. if (rlen != len * 2 || len < 2)
  110. return;
  111. if (response[len - 2] != 0x91)
  112. return;
  113. /* We have a proactive command pending, FETCH it */
  114. at_sim_fetch_command(spd->stk, response[len - 1]);
  115. }
  116. static gboolean sim_status_poll(gpointer user_data)
  117. {
  118. struct sim_poll_data *spd = user_data;
  119. spd->poll_timeout = 0;
  120. /* The SIM must respond in a given time frame which is of at
  121. * least 5 seconds in TS 11.11. */
  122. spd->status_timeout = g_timeout_add_seconds(5,
  123. sim_status_timeout, spd);
  124. /* Send STATUS */
  125. spd->status_cmd = g_at_chat_send(spd->chat, "AT+CSIM=8,A0F200C0",
  126. csim_prefix, at_csim_status_cb, spd, NULL);
  127. if (spd->status_cmd == 0)
  128. at_csim_status_cb(FALSE, NULL, spd);
  129. return FALSE;
  130. }
  131. static void sim_state_watch(enum ofono_sim_state new_state, void *user)
  132. {
  133. struct sim_poll_data *spd = user;
  134. spd->inserted = new_state != OFONO_SIM_STATE_NOT_PRESENT;
  135. if (!spd->inserted)
  136. ofono_modem_set_integer(spd->modem,
  137. "status-poll-interval", 30);
  138. }
  139. static void sim_watch(struct ofono_atom *atom,
  140. enum ofono_atom_watch_condition cond, void *data)
  141. {
  142. struct sim_poll_data *spd = data;
  143. if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) {
  144. spd->sim = __ofono_atom_get_data(atom);
  145. spd->sim_state_watch = ofono_sim_add_state_watch(spd->sim,
  146. sim_state_watch, spd, NULL);
  147. sim_state_watch(ofono_sim_get_state(spd->sim), spd);
  148. sim_status_poll(spd);
  149. return;
  150. }
  151. if (cond != OFONO_ATOM_WATCH_CONDITION_UNREGISTERED)
  152. return;
  153. spd->inserted = FALSE;
  154. spd->sim_state_watch = 0;
  155. if (spd->sim_watch) {
  156. __ofono_modem_remove_atom_watch(spd->modem, spd->sim_watch);
  157. spd->sim_watch = 0;
  158. }
  159. if (spd->stk_watch) {
  160. __ofono_modem_remove_atom_watch(spd->modem, spd->stk_watch);
  161. spd->stk_watch = 0;
  162. }
  163. if (spd->status_timeout) {
  164. g_source_remove(spd->status_timeout);
  165. spd->status_timeout = 0;
  166. }
  167. if (spd->poll_timeout) {
  168. g_source_remove(spd->poll_timeout);
  169. spd->poll_timeout = 0;
  170. }
  171. g_free(spd);
  172. }
  173. static void stk_watch(struct ofono_atom *atom,
  174. enum ofono_atom_watch_condition cond, void *data)
  175. {
  176. struct sim_poll_data *spd = data;
  177. if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED)
  178. spd->stk = __ofono_atom_get_data(atom);
  179. else if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED)
  180. spd->stk = NULL;
  181. }
  182. void atmodem_poll_enable(struct ofono_modem *modem, GAtChat *chat)
  183. {
  184. struct sim_poll_data *spd;
  185. if (__ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_SIM) == NULL)
  186. return;
  187. spd = g_new0(struct sim_poll_data, 1);
  188. spd->chat = chat;
  189. spd->modem = modem;
  190. spd->idle_poll_interval = 30;
  191. spd->stk_watch = __ofono_modem_add_atom_watch(spd->modem,
  192. OFONO_ATOM_TYPE_STK, stk_watch, spd, NULL);
  193. spd->sim_watch = __ofono_modem_add_atom_watch(spd->modem,
  194. OFONO_ATOM_TYPE_SIM, sim_watch, spd, NULL);
  195. }