Code cleanup
[platform/core/telephony/tel-plugin-imc.git] / src / imc_sap.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
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 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <glib.h>
24
25 #include <tcore.h>
26 #include <server.h>
27 #include <plugin.h>
28 #include <core_object.h>
29 #include <hal.h>
30 #include <queue.h>
31 #include <storage.h>
32 #include <at.h>
33
34 #include <co_sap.h>
35
36 #include "imc_sap.h"
37 #include "imc_common.h"
38
39 static TelSapResult __map_sap_status_to_result(int sap_status)
40 {
41         switch(sap_status){
42         case 0:
43                 return TEL_SAP_RESULT_SUCCESS;
44         case 1:
45                 return TEL_SAP_RESULT_FAILURE_NO_REASON;
46         case 2:
47                 return TEL_SAP_RESULT_CARD_NOT_ACCESSIBLE;
48         case 3:
49                 return TEL_SAP_RESULT_CARD_ALREADY_POWERED_OFF;
50         case 4:
51                 return TEL_SAP_RESULT_CARD_REMOVED;
52         case 5:
53                 return TEL_SAP_RESULT_CARD_ALREADY_POWERED_ON;
54         case 6:
55                 return TEL_SAP_RESULT_DATA_NOT_AVAILABLE;
56         case 7:
57                 return TEL_SAP_RESULT_NOT_SUPPORTED;
58         default:
59                 return TEL_SAP_RESULT_FAILURE_NO_REASON;
60         }
61 }
62
63 /* Notification */
64 static gboolean on_notification_imc_sap_status(CoreObject *co,
65         const void *event_info, void *user_data)
66 {
67         GSList *tokens = NULL;
68         GSList *lines = NULL;
69         const char *line = NULL;
70         TelSapCardStatus status;
71
72         dbg("Entry");
73
74         lines = (GSList *) event_info;
75         if (g_slist_length(lines) != 1) {
76                 err("unsolicited msg but multiple lines");
77                 return FALSE;
78         }
79
80         line = (char *)lines->data;
81         tokens = tcore_at_tok_new(line);
82         tcore_check_return_value(tokens != NULL, FALSE);
83
84         status = atoi(g_slist_nth_data(tokens, 0));
85
86         switch(status){
87         case 0:
88                 status = TEL_SAP_CARD_STATUS_UNKNOWN;
89                 break;
90         case 1:
91                 status = TEL_SAP_CARD_STATUS_RESET;
92                 break;
93         case 2:
94                 status = TEL_SAP_CARD_STATUS_NOT_ACCESSIBLE;
95                 break;
96         case 3:
97                 status = TEL_SAP_CARD_STATUS_REMOVED;
98                 break;
99         case 4:
100                 status = TEL_SAP_CARD_STATUS_INSERTED;
101                 break;
102         case 5:
103                 status = TEL_SAP_CARD_STATUS_RECOVERED;
104                 break;
105         default:
106                 status = TEL_SAP_CARD_STATUS_NOT_ACCESSIBLE;
107                 break;
108         }
109
110         tcore_at_tok_free(tokens);
111         tcore_object_send_notification(co,
112                 TCORE_NOTIFICATION_SAP_STATUS,
113                 sizeof(TelSapCardStatus), &status);
114         return TRUE;
115 }
116
117 /* Response */
118 static void on_response_imc_sap_req_connect(TcorePending *p,
119         guint data_len, const void *data, void *user_data)
120 {
121         const TcoreAtResponse *at_resp = data;
122         CoreObject *co = tcore_pending_ref_core_object(p);
123         ImcRespCbData *resp_cb_data = user_data;
124         TelSapResult result = TEL_SAP_RESULT_UNABLE_TO_ESTABLISH;
125         unsigned int max_msg_size = 0;
126         dbg("entry");
127
128         tcore_check_return_assert(co != NULL);
129         tcore_check_return_assert(resp_cb_data != NULL);
130
131         if (at_resp && at_resp->success) {
132                 result = TEL_SAP_RESULT_SUCCESS;
133                 memcpy(&max_msg_size, IMC_GET_DATA_FROM_RESP_CB_DATA(resp_cb_data), sizeof(unsigned int));
134         } else {
135                 err("CME error[%s]", at_resp->lines->data);
136                 /*TODO - need to map CME error to TelSapResult */
137         }
138
139         dbg("Request to sap connection : [%s]",
140         (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
141
142         /* Invoke callback */
143         if (resp_cb_data->cb)
144                 resp_cb_data->cb(co, (gint)result, &max_msg_size, resp_cb_data->cb_data);
145
146         /* Free callback data */
147         imc_destroy_resp_cb_data(resp_cb_data);
148 }
149
150 static void on_response_imc_sap_req_disconnect(TcorePending *p,
151         guint data_len, const void *data, void *user_data)
152 {
153         const TcoreAtResponse *at_resp = data;
154         CoreObject *co = tcore_pending_ref_core_object(p);
155         ImcRespCbData *resp_cb_data = user_data;
156         TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
157         dbg("entry");
158
159         tcore_check_return_assert(co != NULL);
160         tcore_check_return_assert(resp_cb_data != NULL);
161
162         if (at_resp && at_resp->success) {
163                 result = TEL_SAP_RESULT_SUCCESS;
164         } else {
165                 err("CME error[%s]", at_resp->lines->data);
166                 /*TODO - need to map CME error to TelSapResult */
167         }
168
169         dbg("Request to sap connection : [%s]",
170         (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
171
172         /* Invoke callback */
173         if (resp_cb_data->cb)
174                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
175
176         /* Free callback data */
177         imc_destroy_resp_cb_data(resp_cb_data);
178 }
179
180 static void on_response_imc_sap_get_atr(TcorePending *p,
181         guint data_len, const void *data, void *user_data)
182 {
183         const TcoreAtResponse *at_resp = data;
184         CoreObject *co = tcore_pending_ref_core_object(p);
185         ImcRespCbData *resp_cb_data = user_data;
186         TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
187         TelSapAtr atr_resp = {0,};
188
189         dbg("entry");
190
191         if (at_resp && at_resp->success) {
192                 const gchar *line;
193                 char *atr_data;
194                 GSList *tokens = NULL;
195
196                 dbg("RESPONSE OK");
197                 if (at_resp->lines == NULL) {
198                         err("invalid response recieved");
199                         goto END;
200                 }
201
202                 line = (const char*)at_resp->lines->data;
203                 tokens = tcore_at_tok_new(line);
204                 if (g_slist_length(tokens) < 1) {
205                         err("invalid response message");
206                         tcore_at_tok_free(tokens);
207                         goto END;
208                 }
209                 atr_data = (char *) g_slist_nth_data(tokens, 1);
210                 atr_resp.atr_len = strlen(atr_data);
211                 if (atr_resp.atr_len > TEL_SAP_ATR_LEN_MAX) {
212                         err(" invalid atr data length");
213                         tcore_at_tok_free(tokens);
214                         goto END;
215                 }
216                 memcpy(atr_resp.atr, atr_data, atr_resp.atr_len);
217
218                 result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0)));
219                 tcore_at_tok_free(tokens);
220         } else {
221                 err("RESPONSE NOK");
222         }
223
224 END:
225         dbg("Request to get sap atr : [%s]",
226                 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
227
228         /* Invoke callback */
229         if (resp_cb_data->cb)
230                 resp_cb_data->cb(co, (gint)result, &atr_resp, resp_cb_data->cb_data);
231
232         /* Free callback data */
233         imc_destroy_resp_cb_data(resp_cb_data);
234 }
235
236 static void on_response_imc_sap_req_transfer_apdu(TcorePending *p,
237         guint data_len, const void *data, void *user_data)
238 {
239         const TcoreAtResponse *at_resp = data;
240         CoreObject *co = tcore_pending_ref_core_object(p);
241         ImcRespCbData *resp_cb_data = user_data;
242         TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
243         TelSapApduResp apdu_resp = {0,};
244
245         dbg("entry");
246
247         if (at_resp && at_resp->success) {
248                 const gchar *line;
249                 int sap_status;
250                 char *apdu_data;
251                 GSList *tokens = NULL;
252
253                 dbg("RESPONSE OK");
254                 if (at_resp->lines == NULL) {
255                         err("invalid response recieved");
256                         goto END;
257                 }
258
259                 line = (const char*)at_resp->lines->data;
260                 tokens = tcore_at_tok_new(line);
261                 if (g_slist_length(tokens) < 1) {
262                         err("invalid response message");
263                         tcore_at_tok_free(tokens);
264                         goto END;
265                 }
266
267                 apdu_data = (char *) g_slist_nth_data(tokens, 1);
268                 apdu_resp.apdu_resp_len = strlen(apdu_data);
269                 if (apdu_resp.apdu_resp_len > TEL_SAP_APDU_RESP_LEN_MAX) {
270                         err(" invalid apdu data length");
271                         tcore_at_tok_free(tokens);
272                         goto END;
273                 }
274                 memcpy(apdu_resp.apdu_resp, apdu_data, apdu_resp.apdu_resp_len);
275
276                 sap_status = atoi(g_slist_nth_data(tokens, 0));
277                 if (sap_status > 4)
278                 /* In this case modem does not provide sap_status 5 ('Card already powered ON'),
279                    instead it will provide status 5 ('Data not available') and 6 ('Not Supported'),
280                    So to align 'sap_status' value with __map_sap_status_to_result(), it is increased by 1.
281                 */
282                         result = __map_sap_status_to_result(sap_status + 1);
283                 else
284                         result = __map_sap_status_to_result(sap_status);
285
286                 tcore_at_tok_free(tokens);
287         } else {
288                 err("RESPONSE NOK");
289         }
290
291 END:
292         dbg("Request to transfer apdu : [%s]",
293                 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
294
295         /* Invoke callback */
296         if (resp_cb_data->cb)
297                 resp_cb_data->cb(co, (gint)result, &apdu_resp, resp_cb_data->cb_data);
298
299         /* Free callback data */
300         imc_destroy_resp_cb_data(resp_cb_data);
301 }
302
303 static void on_response_imc_sap_req_power_operation(TcorePending *p,
304         guint data_len, const void *data, void *user_data)
305 {
306         const TcoreAtResponse *at_resp = data;
307         CoreObject *co = tcore_pending_ref_core_object(p);
308         ImcRespCbData *resp_cb_data = user_data;
309         TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
310
311         dbg("entry");
312
313         if (at_resp && at_resp->success) {
314                 const gchar *line;
315                 GSList *tokens = NULL;
316
317                 dbg("RESPONSE OK");
318                 if (at_resp->lines == NULL) {
319                         err("invalid response recieved");
320                         goto END;
321                 }
322
323                 line = (const char*)at_resp->lines->data;
324                 tokens = tcore_at_tok_new(line);
325                 if (g_slist_length(tokens) < 1) {
326                         err("invalid response message");
327                         tcore_at_tok_free(tokens);
328                         goto END;
329                 }
330                 result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0)));
331                 tcore_at_tok_free(tokens);
332         } else {
333                 err("RESPONSE NOK");
334         }
335
336 END:
337         dbg("Request to sap power operation : [%s]",
338                 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
339
340         /* Invoke callback */
341         if (resp_cb_data->cb)
342                 resp_cb_data->cb(co, (gint)result, NULL, resp_cb_data->cb_data);
343
344         /* Free callback data */
345         imc_destroy_resp_cb_data(resp_cb_data);
346 }
347
348 static void on_response_imc_sap_get_cardreader_status(TcorePending *p,
349         guint data_len, const void *data, void *user_data)
350 {
351         const TcoreAtResponse *at_resp = data;
352         CoreObject *co = tcore_pending_ref_core_object(p);
353         ImcRespCbData *resp_cb_data = user_data;
354         TelSapResult result = TEL_SAP_RESULT_FAILURE_NO_REASON;
355         TelSapCardStatus card_status = TEL_SAP_CARD_STATUS_UNKNOWN;
356         dbg("entry");
357
358         if (at_resp && at_resp->success) {
359                 const gchar *line;
360                 GSList *tokens = NULL;
361                 unsigned char card_reader_status;
362                 int count;
363
364                 dbg("RESPONSE OK");
365                 if (at_resp->lines == NULL) {
366                         err("invalid response recieved");
367                         goto END;
368                 }
369
370                 line = (const char*)at_resp->lines->data;
371                 tokens = tcore_at_tok_new(line);
372                 if (g_slist_length(tokens) < 1) {
373                         err("invalid response message");
374                         tcore_at_tok_free(tokens);
375                         goto END;
376                 }
377                 result = __map_sap_status_to_result(atoi(g_slist_nth_data(tokens, 0)));
378
379                 card_reader_status = (unsigned char)atoi(g_slist_nth_data(tokens, 1));
380         card_reader_status = card_reader_status >> 3;
381                 for (count = 8; count > 3; count--) { //check bit 8 to 3
382                         if ((card_reader_status & 0x80) == TRUE) { //Check most significant bit
383                                 //card_status =  //TODO - Need to map card reader status to TelSapCardStatus.
384                                 break;
385                         }
386                         card_reader_status = card_reader_status << 1; //left shift by 1
387                 }
388                 tcore_at_tok_free(tokens);
389         } else {
390                 err("RESPONSE NOK");
391                 result = TEL_SAP_RESULT_FAILURE_NO_REASON;
392         }
393
394 END:
395         dbg("Request to get card reader status : [%s]",
396                 (result == TEL_SAP_RESULT_SUCCESS ? "SUCCESS" : "FAIL"));
397
398         /* Invoke callback */
399         if (resp_cb_data->cb)
400                 resp_cb_data->cb(co, (gint)result, &card_status, resp_cb_data->cb_data);
401
402         /* Free callback data */
403         imc_destroy_resp_cb_data(resp_cb_data);
404 }
405
406 /* Sap operations */
407
408 /*
409  * Operation - switch the modem to the  BT SAP server mode.
410  *
411  * Request -
412  * AT-Command: AT+ XBCON = <op_mode>, <change_mode>, <reject_mode>
413  * where,
414  * <op_mode>
415  * 0 - BT SAP Server modes
416  * 1 - BT SAP Client mode (Client mode is currently not supported)
417  * <change_mode>
418  * 0 - gracefully, or Time out
419  * 1 - immediately
420  * <reject_mode>
421  * 0 - Reject is not allowed.
422  * 1 - Reject is allowed.
423  * Response -
424  * Success: (No Result)
425  *      OK
426  * Failure:
427  *      +CME ERROR: <error>
428  */
429 static TelReturn imc_sap_req_connect(CoreObject *co, unsigned int max_msg_size,
430         TcoreObjectResponseCallback cb, void *cb_data)
431 {
432         ImcRespCbData *resp_cb_data;
433         TelReturn ret;
434
435         /* Response callback data */
436         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
437                                 &max_msg_size, sizeof(unsigned int));
438
439         /* Send Request to modem */
440         ret = tcore_at_prepare_and_send_request(co,
441                 "AT+XBCON=0,0,0", NULL,
442                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
443                 NULL,
444                 on_response_imc_sap_req_connect, resp_cb_data,
445                 on_send_imc_request, NULL);
446         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_connect");
447
448         return ret;
449 }
450
451 /*
452  * Operation - disconnects BT SAP.
453  *
454  * Request -
455  * AT-Command: AT+ XBDISC
456  *
457  * Response -
458  * Success: (No Result)
459  *      OK
460  * Failure:
461  *      +CME ERROR: <error>
462  */
463 static TelReturn imc_sap_req_disconnect(CoreObject *co, TcoreObjectResponseCallback cb,
464         void *cb_data)
465 {
466         ImcRespCbData *resp_cb_data;
467         TelReturn ret;
468
469         /* Response callback data */
470         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
471                                 NULL, 0);
472
473         /* Send Request to modem */
474         ret = tcore_at_prepare_and_send_request(co,
475                 "AT+XBDISC", NULL,
476                 TCORE_AT_COMMAND_TYPE_NO_RESULT,
477                 NULL,
478                 on_response_imc_sap_req_disconnect, resp_cb_data,
479                 on_send_imc_request, NULL);
480         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_disconnect");
481
482         return ret;
483 }
484
485 /*
486  * Operation - In BT SAP server mode, request the ATR from the stack to the Application.
487  *
488  * Request -
489  * AT-Command: AT+ XBATR
490  *
491  * Response -
492  * Success: +XBATR: <status>, <data_ATR>
493  * OK
494  * where
495  * <status>
496  * 0 OK, request processed correctly
497  * 1 No Reason defined
498  * 2 Card not accessible
499  * 3 Card (already) powered off
500  * 4 Card Removed
501  * 6 Data Not available
502  * 7 Not Supported
503  * <data_ATR>
504  * Hex Data (an array of bytes)
505  *
506  * Failure:
507  *      +CME ERROR: <error>
508  */
509 static TelReturn imc_sap_get_atr(CoreObject *co, TcoreObjectResponseCallback cb,
510         void *cb_data)
511 {
512         ImcRespCbData *resp_cb_data;
513         TelReturn ret;
514
515         /* Response callback data */
516         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
517                                 NULL, 0);
518
519         /* Send Request to modem */
520         ret = tcore_at_prepare_and_send_request(co,
521                 "AT+XBATR", "+XBATR:",
522                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
523                 NULL,
524                 on_response_imc_sap_get_atr, resp_cb_data,
525                 on_send_imc_request, NULL);
526         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_get_atr");
527
528         return ret;
529 }
530
531 /*
532  * Operation - BT SAP server mode, Forward command APDU from application to SIM.
533  *
534  * Request -
535  * AT-Command: AT+ XBAPDU = <data: command_APDU >
536  * where
537  * <data: command_APDU >
538  * Hex Data (an array of bytes). CP supports Command_APDU up to 261 bytes long.
539  *
540  * Response -
541  * Success: +XBAPDU: <status>, [<data:Response_APDU>]
542  * OK
543  * where
544  * <status>
545  * 0 OK, request processed correctly
546  * 1 No Reason defined
547  * 2 Card not accessible
548  * 3 Card (already) powered off
549  * 4 Card Removed
550  * 5 Data not available
551  * 6 Not Supported
552  * <data:Response_APDU>
553  * Hex Data (an array of bytes). CP supports Response_APDU up to 258 bytes long
554  * Failure:
555  * +CME ERROR: <error>
556  */
557 static TelReturn imc_sap_req_transfer_apdu(CoreObject *co, const TelSapApdu *apdu_data,
558         TcoreObjectResponseCallback cb, void *cb_data)
559 {
560         ImcRespCbData *resp_cb_data;
561         TelReturn ret;
562         gchar *at_cmd;
563
564         /* AT-Command */
565         at_cmd = g_strdup_printf("AT+XBAPDU=\"%s\"", apdu_data->apdu);
566
567         /* Response callback data */
568         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
569                                 NULL, 0);
570
571         /* Send Request to modem */
572         ret = tcore_at_prepare_and_send_request(co,
573                 at_cmd, "+XBAPDU:",
574                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
575                 NULL,
576                 on_response_imc_sap_req_transfer_apdu, resp_cb_data,
577                 on_send_imc_request, NULL);
578         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_transfer_apdu");
579
580         g_free(at_cmd);
581         return ret;
582 }
583
584 static TelReturn imc_sap_req_transport_protocol(CoreObject *co, TelSimSapProtocol protocol,
585         TcoreObjectResponseCallback cb, void *cb_data)
586 {
587         err("Operation not supported");
588         return TEL_RETURN_OPERATION_NOT_SUPPORTED;
589 }
590
591 /*
592  * Operation - In BT SAP server mode, Power ON,OFF and Reset the SIM.
593  *
594  * Request -
595  * AT-Command: AT+ XBPWR =<action>
596  * where
597  * <Action>:
598  * 0 SIM Power ON
599  * 1 SIM Power OFF
600  * 2 SIM RESET
601  *
602  * Response -
603  * Success: + XBPWR: <status>
604  * OK
605  * where
606  * <status>
607  * 0 OK, Request processed correctly
608  * 1 Error no reason defined
609  * 2 Card not Accessible
610  * 3 Card already powered OFF
611  * 4 Card removed
612  * 5 Card already powered ON
613  * 6 Data Not vailable
614  * 7 Not Supported
615  * Failure:
616  * +CME ERROR: <error>
617  */
618 static TelReturn imc_sap_req_power_operation(CoreObject *co, TelSapPowerMode power_mode,
619         TcoreObjectResponseCallback cb, void *cb_data)
620 {
621         ImcRespCbData *resp_cb_data;
622         TelReturn ret = TEL_RETURN_FAILURE;
623         gchar *at_cmd;
624         int action;
625
626         if(power_mode == TEL_SAP_SIM_POWER_ON_REQ) {
627                 action = 0;
628         } else if(power_mode == TEL_SAP_SIM_POWER_OFF_REQ) {
629                 action  = 1;
630         } else if (power_mode == TEL_SAP_SIM_RESET_REQ) {
631                 action = 2;
632         } else {
633                 err("invalid power mode");
634                 return ret;
635         }
636
637         /* AT-Command */
638         at_cmd = g_strdup_printf("AT+XBPWR=%d", action);
639
640         /* Response callback data */
641         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
642                                 NULL, 0);
643
644         /* Send Request to modem */
645         ret = tcore_at_prepare_and_send_request(co,
646                 at_cmd, "+XBPWR:",
647                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
648                 NULL,
649                 on_response_imc_sap_req_power_operation, resp_cb_data,
650                 on_send_imc_request, NULL);
651         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_req_power_operation");
652
653         g_free(at_cmd);
654         return ret;
655 }
656
657 /*
658  * Operation - In BT SAP server mode, get the Card reader Status.
659  *
660  * Request -
661  * AT-Command: AT+XBCRDSTAT
662  *
663  * Response -
664  * Success: +XBCRDSTAT: <status>, <card_reader_status>
665  * OK
666  * where
667  * <status>
668  * 0 OK, Request processed correctly
669  * 1 Error no reason defined
670  * 2 Card not Accessible
671  * 3 Card already powered OFF
672  * 4 Card removed
673  * 5 Card already powered ON
674  * 6 Data Not vailable
675  * 7 Not Supported
676  * <card_reader_status>
677  * One byte. It represents card reader identity and status.
678  * The value of this byte indicates the identity and status of a card reader.
679  * Bits 1-3 = identity of card reader x.
680  * bit 4, 0 = Card reader is not removable, 1 = Card reader is removable
681  * bit 5, 0 = Card reader is not present, 1 = Card reader is present
682  * bit 6, 0 = Card reader present is not ID-1 size, 1 = Card reader present is ID-1 size
683  * bit 7, 0 = No card present, 1 = Card is present in reader
684  * bit 8, 0 = No card powered, 1 = Card in reader is powered
685  * Failure:
686  * +CME ERROR: <error>
687  */
688 static TelReturn imc_sap_get_cardreader_status(CoreObject *co, TcoreObjectResponseCallback cb,
689         void *cb_data)
690 {
691         ImcRespCbData *resp_cb_data;
692         TelReturn ret;
693
694         /* Response callback data */
695         resp_cb_data = imc_create_resp_cb_data(cb, cb_data,
696                                 NULL, 0);
697
698         /* Send Request to modem */
699         ret = tcore_at_prepare_and_send_request(co,
700                 "AT+XBCRDSTAT", "+XBCRDSTAT:",
701                 TCORE_AT_COMMAND_TYPE_SINGLELINE,
702                 NULL,
703                 on_response_imc_sap_get_cardreader_status, resp_cb_data,
704                 on_send_imc_request, NULL);
705         IMC_CHECK_REQUEST_RET(ret, resp_cb_data, "imc_sap_get_cardreader_status");
706
707         return ret;
708 }
709
710 /* SAP Operations */
711 static TcoreSapOps imc_sap_ops = {
712         .req_connect = imc_sap_req_connect,
713         .req_disconnect = imc_sap_req_disconnect,
714         .get_atr = imc_sap_get_atr,
715         .req_transfer_apdu = imc_sap_req_transfer_apdu,
716         .req_transport_protocol = imc_sap_req_transport_protocol,
717         .req_power_operation = imc_sap_req_power_operation,
718         .get_cardreader_status = imc_sap_get_cardreader_status
719 };
720
721 gboolean imc_sap_init(TcorePlugin *p, CoreObject *co)
722 {
723         dbg("Entry");
724
725         /* Set operations */
726         tcore_sap_set_ops(co, &imc_sap_ops);
727
728         /* Add Callbacks */
729         tcore_object_add_callback(co, "+XBCSTAT", on_notification_imc_sap_status, NULL);
730
731         dbg("Exit");
732         return TRUE;
733 }
734
735 void imc_sap_exit(TcorePlugin *p, CoreObject *co)
736 {
737         dbg("Exit");
738 }