/* TODO/BUGS in no order: should send acknowledgement when an sms is read from /phone/sms, not just on every read consider notifying RIL of screen state using RIL_REQUEST_SCREEN_STATE to conserve power too many assumptions made in loop_for_data() about read() giving exactly the right amount of data parcel code will go crazy if ints overflow need to support DTMF*/ #include "dat.h"#include "fns.h"#include "error.h"#include "version.h"#include "mp.h"#include "libsec.h"#include "keyboard.h"#include <stdio.h>#include <cutils/sockets.h>#include <stdlib.h>#include <telephony/ril.h>#include <cutils/jstring.h>#include <arpa/inet.h>#include <libgen.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <semaphore.h>#include <dlfcn.h>#include "smsutils.h"#include "parcel.h" // RIL-related definitions #define RESPONSE_SOLICITED 0#define RESPONSE_UNSOLICITED 1#define POWER_ON 2000#define POWER_OFF 2001 // Inferno-related globals enum{ Qdir, Qctl, Qsms, Qphone, Qsignal, Qstatus, Qcalls}; Dirtab phonetab[] ={ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "ctl", {Qctl}, 0, 0666, "sms", {Qsms}, 0, 0666, "phone", {Qphone}, 0, 0666, "signal", {Qsignal}, 0, 0666, "status", {Qstatus}, 0, 0666, "calls", {Qcalls}, 0, 0666,}; static int signal_strength;static int fd;static int power_state = 0; static struct { QLock l; Rendez r; int ready; int used; char *msg;} status_msg; static struct { QLock l; Rendez r; int ready; int used; // cat will read until it gets 0 bytes from read() // need to be able to give cat 0 bytes after it's gotten the // data RIL_Call *cs; int num; // number of calls in cs} calls; static struct listener_node *phone_listeners = NULL;static struct listener_node *sms_listeners = NULL; static void loop_for_data(void *v);static void send_sms(char *smsc_pdu, char *pdu);static void dial(char *number);static void activate_net(void);static void deactivate_net(void);static void radio_power(int power);static void answer(void);static void acknowledge_sms(void);static void get_reg_state(void);static void set_mute(int);static void get_current_calls(void);static void hangup(int);static void hangup_current(void); // AudioFlinger layer stuffstatic void *af_handle; void (*af_setMode)(int);void (*af_setVoiceVolume)(float);void (*af_setParameters)(char *);void (*af_test)(void); enum audio_mode { MODE_INVALID = -2, MODE_CURRENT = -1, MODE_NORMAL = 0, MODE_RINGTONE, MODE_IN_CALL, MODE_IN_COMMUNICATION, NUM_MODES // not a valid entry, denotes end-of-list}; #define DPRINT if(1) print // Function for Sleep() to check readiness withstatic intcalls_ready(void *unused){ return calls.ready;} // Function for Sleep() to check readiness withstatic intstatus_ready(void *unused){ return status_msg.ready;} voidphoneinit(void){ af_handle = dlopen("libinfernoaudio.so", RTLD_NOW); if(af_handle == NULL) { fprintf(stderr, "opening libinfernoaudio.so failed: %s\n", dlerror()); } af_setMode = dlsym(af_handle, "af_setMode"); af_setVoiceVolume = dlsym(af_handle, "af_setVoiceVolume"); af_setParameters = dlsym(af_handle, "af_setParameters"); if(!(af_setMode && af_setVoiceVolume && af_setParameters)) { fprintf(stderr, "could not load AudioFlinger functions"); dlclose(af_handle); } af_setMode(MODE_NORMAL); calls.cs = NULL; calls.num = 0; calls.ready = 0; calls.used = 0; memset(&calls.l, 0, sizeof(QLock)); status_msg.ready = 0; status_msg.used = 0; memset(&status_msg.l, 0, sizeof(QLock)); // set up proper permissions (need to be user radio, group radio to // access socket) if(setegid(1001) == -1) { perror("setegid(1001) failed"); } if(seteuid(1001) == -1) { perror("seteuid(1001) failed"); } fd = socket_local_client("rild", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if(fd == -1) { perror("socket_local_client failed"); } // set privileges back to root/root if(seteuid(0) == -1) { perror("seteuid(0) failed"); } if(setegid(0) == -1) { perror("setegid(0) failed"); } kproc("phone", loop_for_data, 0, 0);} static Chan*phoneattach(char *spec){ // setup kprocs if necessary return devattach('f', spec);} static Walkqid*phonewalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, phonetab, nelem(phonetab), devgen);} static intphonestat(Chan *c, uchar *db, int n){ return devstat(c, db, n, phonetab, nelem(phonetab), devgen);} static Chan*phoneopen(Chan *c, int omode){ c = devopen(c, omode, phonetab, nelem(phonetab), devgen); switch((ulong) c->qid.path) { case Qstatus: qlock(&status_msg.l); status_msg.used = 0; status_msg.ready = 0; get_reg_state(); break; case Qcalls: qlock(&calls.l); calls.used = 0; calls.ready = 0; get_current_calls(); break; case Qphone: c->aux = qopen(512, 0, nil, nil); add_listener(&phone_listeners, c->aux); break; case Qsms: c->aux = qopen(512, 0, nil, nil); add_listener(&sms_listeners, c->aux); break; } return c;} static voidphoneclose(Chan *c){ if((c->flag & COPEN) == 0) return; switch((ulong) c->qid.path) { case Qphone: del_listener(&phone_listeners, c->aux); qfree(c->aux); c->aux = NULL; break; case Qsms: del_listener(&sms_listeners, c->aux); qfree(c->aux); c->aux = NULL; break; }} static longphoneread(Chan *c, void *va, long n, vlong offset){ char buf[255]; int i, str_offset; if(c->qid.type & QTDIR) { return devdirread(c, va, n, phonetab, nelem(phonetab), devgen); } switch((ulong) c->qid.path) { case Qctl: return readstr(offset, va, n, power_state ? "on\n" : "off\n"); case Qphone: return qread(c->aux, va, n); case Qsms: // FIXME only acknowledge when an SMS is being read acknowledge_sms(); return qread(c->aux, va, n); case Qsignal: snprintf(buf, sizeof(buf), "%d\n", signal_strength); return readstr(offset, va, n, buf); case Qstatus: Sleep(&status_msg.r, status_ready, NULL); if(status_msg.ready == -1) { // an error occurred status_msg.used = 1; qunlock(&status_msg.l); return readstr(offset, va, n, "error\n"); } if(status_msg.used) { status_msg.ready = 0; status_msg.used = 0; return 0; // already sent the data } status_msg.used = 1; return readstr(offset, va, n, status_msg.msg); case Qcalls: Sleep(&calls.r, calls_ready, NULL); if(calls.ready == -1) { // an error occurred calls.used = 1; qunlock(&calls.l); return readstr(offset, va, n, ""); } if(calls.used || calls.num == 0) { calls.ready = 0; calls.used = 0; qunlock(&calls.l); return 0; // already sent the data } calls.used = 1; str_offset = 0; for(i = 0; i < calls.num; i++) { RIL_Call c = calls.cs[i]; str_offset += snprintf(va + str_offset, n - str_offset, "call %d:\n " " state %d\n index %d\n toa %d\n" " isMpty %d\n isMT %d\n als %d\n isVoice %d\n" " isVoicePrivacy %d\n number %s\n" " numberPresentation %d\n name %s\n" " namePresentation %d\n", i, c.state, c.index, c.toa, c.isMpty, c.isMT, c.als, c.isVoice, c.isVoicePrivacy, c.number, c.numberPresentation, c.name, c.namePresentation); } qunlock(&calls.l); return str_offset; } return 0;} static longphonewrite(Chan *c, void *va, long n, vlong offset){ char *pdu; Rune *runestr; int i, j; Cmdbuf *cmd; if(c->qid.type & QTDIR) error(Eperm); cmd = parsecmd(va, n); if(waserror()) { free(cmd); nexterror(); return 0; } switch((ulong) c->qid.path) { case Qctl: if(strcmp(cmd->f[0], "on") == 0) { radio_power(1); } else if(strcmp(cmd->f[0], "off") == 0) { radio_power(0); } else if(strcmp(cmd->f[0], "net") == 0) { if(cmd->nf >= 2) { if(strcmp(cmd->f[1], "on") == 0) { activate_net(); } else if(strcmp(cmd->f[1], "off") == 0) { deactivate_net(); } } } else if(strcmp(cmd->f[0], "mute") == 0) { set_mute(1); } else if(strcmp(cmd->f[0], "unmute") == 0) { set_mute(0); } else if(strcmp(cmd->f[0], "route") == 0) { if(cmd->nf >= 2) { if(strcmp(cmd->f[1], "earpiece") == 0) { af_setParameters("routing=1"); } else if(strcmp(cmd->f[1], "speaker") == 0) { af_setParameters("routing=2"); } else if(strcmp(cmd->f[1], "headphone") == 0) { af_setParameters("routing=3"); } } } else if(strcmp(cmd->f[0], "volume") == 0) { if(cmd->nf >= 2) { switch(strtol(cmd->f[1], NULL, 10)) { case 0: af_setVoiceVolume(0.0); break; case 1: af_setVoiceVolume(0.2); break; case 2: af_setVoiceVolume(0.4); break; case 3: af_setVoiceVolume(0.6); break; case 4: af_setVoiceVolume(0.8); break; case 5: af_setVoiceVolume(1.0); break; default: af_setVoiceVolume(1.0); break; } } } break; case Qsms: if(strcmp(cmd->f[0], "send") == 0) { if(cmd->nf == 3) { runestr = malloc((utflen(cmd->f[2]) + 1) * sizeof(Rune)); for(i = 0, j = 0; j < strlen(cmd->f[2]); i++) { j += chartorune(runestr + i, cmd->f[2] + j); } runestr[i] = 0; pdu = encode_sms(cmd->f[1], runestr); send_sms(NULL, pdu); free(runestr); free(pdu); } } break; case Qphone: if(strcmp(cmd->f[0], "answer") == 0) { answer(); } else if(strcmp(cmd->f[0], "dial") == 0) { if(cmd->nf != 2) { fprintf(stderr, "malformed dial request\n"); break; } dial(cmd->f[1]); } else if(strcmp(cmd->f[0], "hangup") == 0) { if(cmd->nf == 2) { hangup(strtol(cmd->f[1], NULL, 10)); } else { hangup_current(); } } break; } poperror(); free(cmd); return n;} Dev phonedevtab = { 'f', "phone", phoneinit, phoneattach, phonewalk, phonestat, phoneopen, devcreate, phoneclose, phoneread, devbread, phonewrite, devbwrite, devremove, devwstat}; /* RIL functions */ static voidhandle_error(int seq, int error){ // RIL error messages char *errmsgs[] = { "error: no error\n", "error: radio not available\n", "error: generic failure\n", "error: password incorrect\n", "error: need SIM PIN2\n", "error: need SIM PUK2\n", "error: request not supported\n", "error: cancelled\n", "error: cannot access network during voice calls\n", "error: cannot access network before registering to network\n", "error: retry sending sms\n", "error: no SIM\n", "error: no subscription\n", "error: mode not supported\n", "error: FDN list check failed\n", "error: illegal SIM or ME\n" }; char *errmsg = errmsgs[error]; switch(seq) { case RIL_REQUEST_SEND_SMS: listeners_produce(&sms_listeners, errmsg, strlen(errmsg)); break; case RIL_REQUEST_DIAL: listeners_produce(&phone_listeners, errmsg, strlen(errmsg)); break; case RIL_REQUEST_REGISTRATION_STATE: status_msg.ready = -1; Wakeup(&status_msg.r); qunlock(&status_msg.l); break; case RIL_REQUEST_GET_CURRENT_CALLS: calls.ready = -1; Wakeup(&calls.r); qunlock(&calls.l); break; }} /* handle_sol_response is called when we recieve a solicited response from RIL, i.e. the response to a request we sent. The response can contain data we asked for, indicate an error, or simply indicate success. */static voidhandle_sol_response(struct parcel *p){ int seq, error, i, num, offset = 0; char buf[200]; seq = parcel_r_int32(p); error = parcel_r_int32(p); DPRINT("received sol response: seq: %d err: %d\n", seq, error); if(error != 0) { handle_error(seq, error); return; } switch(seq) { case RIL_REQUEST_SETUP_DATA_CALL: if(!parcel_data_avail(p)) return; num = parcel_r_int32(p); for(i = 0; i < num; i++) {Lines 1–500 of 867. Load more
/* TODO/BUGS in no order: should send acknowledgement when an sms is read from /phone/sms, not just on every read consider notifying RIL of screen state using RIL_REQUEST_SCREEN_STATE to conserve power too many assumptions made in loop_for_data() about read() giving exactly the right amount of data parcel code will go crazy if ints overflow need to support DTMF */ #include "dat.h" #include "fns.h" #include "error.h" #include "version.h" #include "mp.h" #include "libsec.h" #include "keyboard.h" #include <stdio.h> #include <cutils/sockets.h> #include <stdlib.h> #include <telephony/ril.h> #include <cutils/jstring.h> #include <arpa/inet.h> #include <libgen.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <semaphore.h> #include <dlfcn.h> #include "smsutils.h" #include "parcel.h" // RIL-related definitions #define RESPONSE_SOLICITED 0 #define RESPONSE_UNSOLICITED 1 #define POWER_ON 2000 #define POWER_OFF 2001 // Inferno-related globals enum { Qdir, Qctl, Qsms, Qphone, Qsignal, Qstatus, Qcalls }; Dirtab phonetab[] = { ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "ctl", {Qctl}, 0, 0666, "sms", {Qsms}, 0, 0666, "phone", {Qphone}, 0, 0666, "signal", {Qsignal}, 0, 0666, "status", {Qstatus}, 0, 0666, "calls", {Qcalls}, 0, 0666, }; static int signal_strength; static int fd; static int power_state = 0; static struct { QLock l; Rendez r; int ready; int used; char *msg; } status_msg; static struct { QLock l; Rendez r; int ready; int used; // cat will read until it gets 0 bytes from read() // need to be able to give cat 0 bytes after it's gotten the // data RIL_Call *cs; int num; // number of calls in cs } calls; static struct listener_node *phone_listeners = NULL; static struct listener_node *sms_listeners = NULL; static void loop_for_data(void *v); static void send_sms(char *smsc_pdu, char *pdu); static void dial(char *number); static void activate_net(void); static void deactivate_net(void); static void radio_power(int power); static void answer(void); static void acknowledge_sms(void); static void get_reg_state(void); static void set_mute(int); static void get_current_calls(void); static void hangup(int); static void hangup_current(void); // AudioFlinger layer stuff static void *af_handle; void (*af_setMode)(int); void (*af_setVoiceVolume)(float); void (*af_setParameters)(char *); void (*af_test)(void); enum audio_mode { MODE_INVALID = -2, MODE_CURRENT = -1, MODE_NORMAL = 0, MODE_RINGTONE, MODE_IN_CALL, MODE_IN_COMMUNICATION, NUM_MODES // not a valid entry, denotes end-of-list }; #define DPRINT if(1) print // Function for Sleep() to check readiness with static int calls_ready(void *unused) { return calls.ready; } // Function for Sleep() to check readiness with static int status_ready(void *unused) { return status_msg.ready; } void phoneinit(void) { af_handle = dlopen("libinfernoaudio.so", RTLD_NOW); if(af_handle == NULL) { fprintf(stderr, "opening libinfernoaudio.so failed: %s\n", dlerror()); } af_setMode = dlsym(af_handle, "af_setMode"); af_setVoiceVolume = dlsym(af_handle, "af_setVoiceVolume"); af_setParameters = dlsym(af_handle, "af_setParameters"); if(!(af_setMode && af_setVoiceVolume && af_setParameters)) { fprintf(stderr, "could not load AudioFlinger functions"); dlclose(af_handle); } af_setMode(MODE_NORMAL); calls.cs = NULL; calls.num = 0; calls.ready = 0; calls.used = 0; memset(&calls.l, 0, sizeof(QLock)); status_msg.ready = 0; status_msg.used = 0; memset(&status_msg.l, 0, sizeof(QLock)); // set up proper permissions (need to be user radio, group radio to // access socket) if(setegid(1001) == -1) { perror("setegid(1001) failed"); } if(seteuid(1001) == -1) { perror("seteuid(1001) failed"); } fd = socket_local_client("rild", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); if(fd == -1) { perror("socket_local_client failed"); } // set privileges back to root/root if(seteuid(0) == -1) { perror("seteuid(0) failed"); } if(setegid(0) == -1) { perror("setegid(0) failed"); } kproc("phone", loop_for_data, 0, 0); } static Chan* phoneattach(char *spec) { // setup kprocs if necessary return devattach('f', spec); } static Walkqid* phonewalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, phonetab, nelem(phonetab), devgen); } static int phonestat(Chan *c, uchar *db, int n) { return devstat(c, db, n, phonetab, nelem(phonetab), devgen); } static Chan* phoneopen(Chan *c, int omode) { c = devopen(c, omode, phonetab, nelem(phonetab), devgen); switch((ulong) c->qid.path) { case Qstatus: qlock(&status_msg.l); status_msg.used = 0; status_msg.ready = 0; get_reg_state(); break; case Qcalls: qlock(&calls.l); calls.used = 0; calls.ready = 0; get_current_calls(); break; case Qphone: c->aux = qopen(512, 0, nil, nil); add_listener(&phone_listeners, c->aux); break; case Qsms: c->aux = qopen(512, 0, nil, nil); add_listener(&sms_listeners, c->aux); break; } return c; } static void phoneclose(Chan *c) { if((c->flag & COPEN) == 0) return; switch((ulong) c->qid.path) { case Qphone: del_listener(&phone_listeners, c->aux); qfree(c->aux); c->aux = NULL; break; case Qsms: del_listener(&sms_listeners, c->aux); qfree(c->aux); c->aux = NULL; break; } } static long phoneread(Chan *c, void *va, long n, vlong offset) { char buf[255]; int i, str_offset; if(c->qid.type & QTDIR) { return devdirread(c, va, n, phonetab, nelem(phonetab), devgen); } switch((ulong) c->qid.path) { case Qctl: return readstr(offset, va, n, power_state ? "on\n" : "off\n"); case Qphone: return qread(c->aux, va, n); case Qsms: // FIXME only acknowledge when an SMS is being read acknowledge_sms(); return qread(c->aux, va, n); case Qsignal: snprintf(buf, sizeof(buf), "%d\n", signal_strength); return readstr(offset, va, n, buf); case Qstatus: Sleep(&status_msg.r, status_ready, NULL); if(status_msg.ready == -1) { // an error occurred status_msg.used = 1; qunlock(&status_msg.l); return readstr(offset, va, n, "error\n"); } if(status_msg.used) { status_msg.ready = 0; status_msg.used = 0; return 0; // already sent the data } status_msg.used = 1; return readstr(offset, va, n, status_msg.msg); case Qcalls: Sleep(&calls.r, calls_ready, NULL); if(calls.ready == -1) { // an error occurred calls.used = 1; qunlock(&calls.l); return readstr(offset, va, n, ""); } if(calls.used || calls.num == 0) { calls.ready = 0; calls.used = 0; qunlock(&calls.l); return 0; // already sent the data } calls.used = 1; str_offset = 0; for(i = 0; i < calls.num; i++) { RIL_Call c = calls.cs[i]; str_offset += snprintf(va + str_offset, n - str_offset, "call %d:\n " " state %d\n index %d\n toa %d\n" " isMpty %d\n isMT %d\n als %d\n isVoice %d\n" " isVoicePrivacy %d\n number %s\n" " numberPresentation %d\n name %s\n" " namePresentation %d\n", i, c.state, c.index, c.toa, c.isMpty, c.isMT, c.als, c.isVoice, c.isVoicePrivacy, c.number, c.numberPresentation, c.name, c.namePresentation); } qunlock(&calls.l); return str_offset; } return 0; } static long phonewrite(Chan *c, void *va, long n, vlong offset) { char *pdu; Rune *runestr; int i, j; Cmdbuf *cmd; if(c->qid.type & QTDIR) error(Eperm); cmd = parsecmd(va, n); if(waserror()) { free(cmd); nexterror(); return 0; } switch((ulong) c->qid.path) { case Qctl: if(strcmp(cmd->f[0], "on") == 0) { radio_power(1); } else if(strcmp(cmd->f[0], "off") == 0) { radio_power(0); } else if(strcmp(cmd->f[0], "net") == 0) { if(cmd->nf >= 2) { if(strcmp(cmd->f[1], "on") == 0) { activate_net(); } else if(strcmp(cmd->f[1], "off") == 0) { deactivate_net(); } } } else if(strcmp(cmd->f[0], "mute") == 0) { set_mute(1); } else if(strcmp(cmd->f[0], "unmute") == 0) { set_mute(0); } else if(strcmp(cmd->f[0], "route") == 0) { if(cmd->nf >= 2) { if(strcmp(cmd->f[1], "earpiece") == 0) { af_setParameters("routing=1"); } else if(strcmp(cmd->f[1], "speaker") == 0) { af_setParameters("routing=2"); } else if(strcmp(cmd->f[1], "headphone") == 0) { af_setParameters("routing=3"); } } } else if(strcmp(cmd->f[0], "volume") == 0) { if(cmd->nf >= 2) { switch(strtol(cmd->f[1], NULL, 10)) { case 0: af_setVoiceVolume(0.0); break; case 1: af_setVoiceVolume(0.2); break; case 2: af_setVoiceVolume(0.4); break; case 3: af_setVoiceVolume(0.6); break; case 4: af_setVoiceVolume(0.8); break; case 5: af_setVoiceVolume(1.0); break; default: af_setVoiceVolume(1.0); break; } } } break; case Qsms: if(strcmp(cmd->f[0], "send") == 0) { if(cmd->nf == 3) { runestr = malloc((utflen(cmd->f[2]) + 1) * sizeof(Rune)); for(i = 0, j = 0; j < strlen(cmd->f[2]); i++) { j += chartorune(runestr + i, cmd->f[2] + j); } runestr[i] = 0; pdu = encode_sms(cmd->f[1], runestr); send_sms(NULL, pdu); free(runestr); free(pdu); } } break; case Qphone: if(strcmp(cmd->f[0], "answer") == 0) { answer(); } else if(strcmp(cmd->f[0], "dial") == 0) { if(cmd->nf != 2) { fprintf(stderr, "malformed dial request\n"); break; } dial(cmd->f[1]); } else if(strcmp(cmd->f[0], "hangup") == 0) { if(cmd->nf == 2) { hangup(strtol(cmd->f[1], NULL, 10)); } else { hangup_current(); } } break; } poperror(); free(cmd); return n; } Dev phonedevtab = { 'f', "phone", phoneinit, phoneattach, phonewalk, phonestat, phoneopen, devcreate, phoneclose, phoneread, devbread, phonewrite, devbwrite, devremove, devwstat }; /* RIL functions */ static void handle_error(int seq, int error) { // RIL error messages char *errmsgs[] = { "error: no error\n", "error: radio not available\n", "error: generic failure\n", "error: password incorrect\n", "error: need SIM PIN2\n", "error: need SIM PUK2\n", "error: request not supported\n", "error: cancelled\n", "error: cannot access network during voice calls\n", "error: cannot access network before registering to network\n", "error: retry sending sms\n", "error: no SIM\n", "error: no subscription\n", "error: mode not supported\n", "error: FDN list check failed\n", "error: illegal SIM or ME\n" }; char *errmsg = errmsgs[error]; switch(seq) { case RIL_REQUEST_SEND_SMS: listeners_produce(&sms_listeners, errmsg, strlen(errmsg)); break; case RIL_REQUEST_DIAL: listeners_produce(&phone_listeners, errmsg, strlen(errmsg)); break; case RIL_REQUEST_REGISTRATION_STATE: status_msg.ready = -1; Wakeup(&status_msg.r); qunlock(&status_msg.l); break; case RIL_REQUEST_GET_CURRENT_CALLS: calls.ready = -1; Wakeup(&calls.r); qunlock(&calls.l); break; } } /* handle_sol_response is called when we recieve a solicited response from RIL, i.e. the response to a request we sent. The response can contain data we asked for, indicate an error, or simply indicate success. */ static void handle_sol_response(struct parcel *p) { int seq, error, i, num, offset = 0; char buf[200]; seq = parcel_r_int32(p); error = parcel_r_int32(p); DPRINT("received sol response: seq: %d err: %d\n", seq, error); if(error != 0) { handle_error(seq, error); return; } switch(seq) { case RIL_REQUEST_SETUP_DATA_CALL: if(!parcel_data_avail(p)) return; num = parcel_r_int32(p); for(i = 0; i < num; i++) {