android_device_htc_leo/libreference-ril/leoreference-ril.c
2011-01-24 22:30:02 +05:30

492 lines
13 KiB
C

/* //device/system/reference-ril/reference-ril.c
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include <telephony/ril.h>
#include <dlfcn.h>
#include <utils/Log.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <alloca.h>
#include "misc.h"
#include <getopt.h>
#include <sys/socket.h>
#include <cutils/sockets.h>
#include <termios.h>
#include <utils/Log.h>
#define LOG_TAG "RILW"
#define RIL_DEBUG 1
#if RIL_DEBUG
# define D(...) LOGD(__VA_ARGS__)
#else
# define D(...) ((void)0)
#endif
#define RIL_onRequestComplete(t, e, response, responselen) s_rilenv->OnRequestComplete(t,e, response, responselen)
#define PPP_TTY_PATH "/dev/ppp0"
#define AT_ERROR_GENERIC -1
#define AT_ERROR_COMMAND_PENDING -2
#define AT_ERROR_CHANNEL_CLOSED -3
#define AT_ERROR_TIMEOUT -4
#define AT_ERROR_INVALID_THREAD -5 /* AT commands may not be issued from
reader thread (or unsolicited response
callback */
#define AT_ERROR_INVALID_RESPONSE -6 /* eg an at_send_command_singleline that
did not get back an intermediate
response */
void (*libhtc_ril_onRequest)(int request, void *data, size_t datalen, RIL_Token t);
static const char * s_device_path = NULL;
static const struct RIL_Env *s_rilenv;
static void *ril_handler=NULL;
static int s_fd = -1; /* fd of the AT channel */
static const char * getVersion(void) {
return "android leo-reference-ril 1.0";
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
void AT_DUMP(const char* prefix, const char* buff, int len) {
if (len < 0)
len = strlen(buff);
D("%.*s", len, buff);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
static int at_writeline (const char *s) {
size_t cur = 0;
size_t len = strlen(s);
ssize_t written;
if (s_fd < 0 ) {
return AT_ERROR_CHANNEL_CLOSED;
}
AT_DUMP( ">> ", s, strlen(s) );
/* the main string */
while (cur < len) {
do {
written = write (s_fd, s + cur, len - cur);
} while (written < 0 && errno == EINTR);
if (written < 0) {
return AT_ERROR_GENERIC;
}
cur += written;
}
/* the \r */
do {
written = write (s_fd, "\r" , 1);
} while ((written < 0 && errno == EINTR) || (written == 0));
if (written < 0) {
return AT_ERROR_GENERIC;
}
//D("AT> %s", "sent");
return 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
static int at_command(char *cmd, int to)
{
fd_set rfds;
struct timeval timeout;
char buf[1024];
int sel, len, i, err;
err=at_writeline(cmd);
if (err != 0 ) {
goto error;
}
//read always failed, not sure why ?
for (i = 0; i < 100; i++) {
FD_ZERO(&rfds);
FD_SET(s_fd, &rfds);
timeout.tv_sec = 0;
timeout.tv_usec = to;
if ((sel = select(s_fd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
if (FD_ISSET(s_fd, &rfds)) {
memset(buf, 0, sizeof(buf));
len = read(s_fd, buf, sizeof(buf));
if (len> 0) {
D("%d: %s", len, buf);
if (strstr(buf, "\r\nOK") != NULL){
D(" > OK");
break;
}
if (strstr(buf, "\r\nERROR") != NULL){
D(" > ERROR");
break;
}
if (strstr(buf, "\r\nCONNECT") != NULL){
D(" > CONNECT");
break;
}
}
}
} else {
//LOGE("select %s: %s (%d)", s_device_path, strerror(errno), errno);
}
}
return 0;
error:
return -1;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
static int open_modem() {
struct termios ios;
int fd;
LOGI("Opening tty device %s", s_device_path);
//
// fd = open(s_device_path, O_RDWR | O_NONBLOCK);
fd = open(s_device_path, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0) {
LOGE("Can't open %s: %s (%d)", s_device_path, strerror(errno), errno);
return -1;
}
tcflush(fd, TCIOFLUSH);
#if 0
/* Switch tty to RAW mode */
tcgetattr( fd, &ios );
/* cfmakeraw(&ios); */
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr(fd, TCSANOW, &ios);
#endif
/* Switch tty to RAW mode */
cfmakeraw(&ios);
tcsetattr(fd, TCSANOW, &ios);
s_fd = fd;
return fd;
}
static int close_modem() {
if (s_fd >= 0) {
close(s_fd);
}
LOGI("Closing tty device %s", s_device_path);
s_fd = -1;
return 0;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
#if 0
int open_modem () {
int fd;
int ret;
struct termios ios;
fd = open (s_device_path, O_RDWR);
if(fd == -1) {
LOGE("Error opening %s", s_device_path);
goto error;
}
/* disable echo on serial ports */
tcgetattr( fd, &ios );
ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
tcsetattr( fd, TCSANOW, &ios );
s_fd = fd;
return 0;
error:
return -1;
}
#endif
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
static void requestRegistrationState(int request, void *data,
size_t datalen, RIL_Token t) {
D("%s", __func__);
if (request == RIL_REQUEST_REGISTRATION_STATE) {
D("### RIL_REQUEST_REGISTRATION_STATE");
} else if (request == RIL_REQUEST_GPRS_REGISTRATION_STATE) {
D("### RIL_REQUEST_GPRS_REGISTRATION_STATE");
}
libhtc_ril_onRequest(request, data, datalen, t);
D("%s:%.*s", __func__ , datalen, (char *)data);
return;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
void requestDeactivateDataCall(void *data, size_t datalen, RIL_Token t)
{
int ret, err;
char * cmd;
char * cid;
int fd;
open_modem();
cid = ((char **)data)[0];
D("%s, cid: %s", __func__, cid);
asprintf(&cmd, "AT+CGACT=0,%s", cid);
err = at_command(cmd, 10000);
free(cmd);
int i=0;
i=0;
while((fd = open("/etc/ppp/ppp0.pid",O_RDONLY)) > 0) {
if(i%5 == 0) system("killall pppd");
close(fd);
if(i>25) goto error;
i++;
sleep(1);
}
close_modem();
D("%s: RIL_E_SUCCESS ", __func__);
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
return;
error:
close_modem();
LOGE("%s: GENERIC_FAILURE ", __func__);
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
static void requestSetupDataCall(char **data, size_t datalen, RIL_Token t) {
const char *apn;
char *user = NULL;
char *pass = NULL;
char *cmd;
char *userpass;
int err;
int fd;
FILE *cfg;
char *buffer;
long buffSize, len;
char *response[2] = { "1", "ppp0" };
int status;
int ret;
D("%s", __func__);
/* check if /dev/ppp exists else pppd will be fail*/
int fd_ppp = open ("/dev/ppp", O_RDWR);
if (fd_ppp == -1) {
system("mknod /dev/ppp c 108 0");
fd_ppp = open ("/dev/ppp", O_RDWR);
if (fd_ppp == -1) LOGE("Error opening /dev/ppp");
}
open_modem();
apn = ((const char **)data)[2];
user = ((char **)data)[3];
pass = ((char **)data)[4];
D("requesting data connection to APN '%s'", apn);
/*at_command("ATZ", 10000);*/
//D("Setting up PDP Context");
asprintf(&cmd, "AT+CGDCONT=1,\"IP\",\"%s\",,0,0", apn);
//FIXME check for error here
err = at_command(cmd, 10000);
free(cmd);
// Set required QoS params to default
err = at_command("AT+CGQREQ=1", 10000);
// Set minimum QoS params to default
err = at_command("AT+CGQMIN=1", 10000);
// packet-domain event reporting
err = at_command("AT+CGEREP=1,0", 10000);
//D("Activating PDP Context");
// Hangup anything that's happening there now
err = at_command("AT+CGACT=1,0", 10000);
//D("Start data on PDP context 1");
err = at_command("ATD*99***1#", 10000);
//err = at_command("ATD*99#", 1);
asprintf(&userpass, "%s * %s", user, pass);
len = strlen(userpass);
fd = open("/etc/ppp/pap-secrets",O_WRONLY);
if(fd < 0) {
D("could not open /etc/ppp/pap-secrets");
goto error;
}
write(fd, userpass, len);
close(fd);
fd = open("/etc/ppp/chap-secrets",O_WRONLY);
if(fd < 0) {
D("could not open /etc/ppp/chap-secrets");
goto error;
}
write(fd, userpass, len);
close(fd);
free(userpass);
cfg = fopen("/etc/ppp/options.smd","r");
if(!cfg) {
D("could not open /etc/ppp/options.smd");
goto error;
}
//filesize
fseek(cfg, 0, SEEK_END);
buffSize = ftell(cfg);
rewind(cfg);
//allocate memory
buffer = (char *) malloc (sizeof(char)*buffSize);
if (buffer == NULL) {
goto error;
}
//read in the original file
len = fread (buffer,1,buffSize,cfg);
if (len != buffSize) {
D("could not set cfg");
goto error;
}
fclose(cfg);
cfg = fopen("/etc/ppp/options.smd1","w");
fwrite(buffer,1,buffSize,cfg);
fprintf(cfg,"user %s",user);
fclose(cfg);
free(buffer);
status = system("/bin/pppd /dev/smd1 debug defaultroute");
if (status == 0) {
sleep(5); // allow time for ip-up to run
/*system("/system/bin/log -t pppd -c1 www.google.com");*/
} else {
LOGE("/bin/pppd failed, status: %d", status);
goto error;
}
/*
inaddr_t addr,mask;
unsigned int flags;
ifc_init();
ifc_get_info(PPP_TTY_PATH, &addr, &mask, &flags);
ifc_close();
*/
close_modem();
D("%s: RIL_E_SUCCESS ", __func__);
RIL_onRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
return;
error:
close_modem();
LOGE("%s: GENERIC_FAILURE ", __func__);
RIL_onRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
void onRequest(int request, void *data, size_t datalen, RIL_Token t) {
switch (request) {
case RIL_REQUEST_SETUP_DATA_CALL:
return requestSetupDataCall(data, datalen, t);
case RIL_REQUEST_DEACTIVATE_DATA_CALL:
return requestDeactivateDataCall(data, datalen, t);
case RIL_REQUEST_REGISTRATION_STATE:
case RIL_REQUEST_GPRS_REGISTRATION_STATE:
return requestRegistrationState(request, data, datalen, t);
default:
return libhtc_ril_onRequest(request, data, datalen, t);
}
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
static void usage(char *s)
{
#ifdef RIL_SHLIB
fprintf(stderr, "leo-reference-ril requires: -p <tcp port> or -d /dev/tty_device");
#else
fprintf(stderr, "usage: %s [-p <tcp port>] [-d /dev/tty_device]", s);
exit(-1);
#endif
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) {
int ret;
int fd = -1;
int opt;
s_rilenv = env;
D("%s", __func__);
while ( -1 != (opt = getopt(argc, argv, "p:d:s:"))) {
switch (opt) {
case 'd':
s_device_path = optarg;
break;
default:
usage(argv[0]);
return NULL;
}
}
if (s_device_path == NULL) {
usage(argv[0]);
return NULL;
}
ril_handler=dlopen("/system/lib/libhtc_ril.so", 0/*Need to RTFM, 0 seems fine*/);
RIL_RadioFunctions* (*htc_ril)(const struct RIL_Env *env, int argc, char **argv);
htc_ril=dlsym(ril_handler, "RIL_Init");
RIL_RadioFunctions *s_callbacks;
s_callbacks=htc_ril(env, argc, argv);
libhtc_ril_onRequest=s_callbacks->onRequest;
s_callbacks->onRequest=onRequest;
return s_callbacks;
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=