summaryrefslogtreecommitdiffstats
path: root/ipc.c
diff options
context:
space:
mode:
authorPaul Kocialkowski <contact@paulk.fr>2014-08-07 13:12:15 +0200
committerPaul Kocialkowski <contact@paulk.fr>2014-08-07 13:12:15 +0200
commita7ff1df1869ce543171a6ee92cbf821647b1bf7d (patch)
tree659e315b3d609f0f9e661d4de21b52077e6e2b81 /ipc.c
parentc8408cd2c116b0b99a399282032b6607a1318b84 (diff)
downloadhardware_ril_samsung-ril-a7ff1df1869ce543171a6ee92cbf821647b1bf7d.zip
hardware_ril_samsung-ril-a7ff1df1869ce543171a6ee92cbf821647b1bf7d.tar.gz
hardware_ril_samsung-ril-a7ff1df1869ce543171a6ee92cbf821647b1bf7d.tar.bz2
Samsung-RIL rewrite: harder, better, probably not faster but definitely stronger
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Diffstat (limited to 'ipc.c')
-rw-r--r--ipc.c1106
1 files changed, 917 insertions, 189 deletions
diff --git a/ipc.c b/ipc.c
index a86a27f..d8601fa 100644
--- a/ipc.c
+++ b/ipc.c
@@ -2,7 +2,7 @@
* This file is part of Samsung-RIL.
*
* Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
- * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
*
* Samsung-RIL is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,364 +18,1092 @@
* along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <stdlib.h>
+#include <sys/eventfd.h>
+
#define LOG_TAG "RIL-IPC"
#include <utils/Log.h>
+#include <hardware_legacy/power.h>
-#include "samsung-ril.h"
+#include <samsung-ril.h>
+#include <utils.h>
/*
- * IPC shared
+ * Utils
*/
void ipc_log_handler(void *log_data, const char *message)
{
- RIL_LOGD("ipc: %s", message);
+ RIL_LOGD("%s", message);
}
/*
* IPC FMT
*/
-void ipc_fmt_send(const unsigned short command, const char type, unsigned char *data, const int length, unsigned char mseq)
-{
- struct ipc_client *ipc_client;
-
- if (ril_data.ipc_fmt_client == NULL || ril_data.ipc_fmt_client->data == NULL)
- return;
-
- ipc_client = (struct ipc_client *) ril_data.ipc_fmt_client->data;
-
- RIL_CLIENT_LOCK(ril_data.ipc_fmt_client);
- ipc_client_send(ipc_client, command, type, data, length, mseq);
- RIL_CLIENT_UNLOCK(ril_data.ipc_fmt_client);
-}
-
-int ipc_fmt_read_loop(struct ril_client *client)
+int ipc_fmt_send(unsigned char mseq, unsigned short command, unsigned char type,
+ const void *data, size_t size)
{
- struct ipc_client *ipc_client;
- struct ipc_message_info info;
-
+ struct ril_client *client;
+ struct ipc_fmt_data *ipc_fmt_data;
int rc;
+ client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
if (client == NULL || client->data == NULL)
- return -EINVAL;
+ return -1;
- ipc_client = (struct ipc_client *) client->data;
+ ipc_fmt_data = (struct ipc_fmt_data *) client->data;
+ if (ipc_fmt_data->ipc_client == NULL || ipc_fmt_data->event_fd < 0)
+ return -1;
- while (1) {
- rc = ipc_client_poll(ipc_client, NULL);
- if (rc < 0) {
- RIL_LOGE("IPC FMT client poll failed, aborting");
- goto error;
- }
-
- memset(&info, 0, sizeof(info));
-
- RIL_CLIENT_LOCK(client);
- if (ipc_client_recv(ipc_client, &info) < 0) {
- RIL_CLIENT_UNLOCK(client);
- RIL_LOGE("IPC FMT recv failed, aborting");
- goto error;
- }
- RIL_CLIENT_UNLOCK(client);
+ if (!client->available) {
+ RIL_LOGE("%s client is not available", client->name);
+ return -1;
+ }
- ipc_fmt_dispatch(&info);
+ RIL_CLIENT_LOCK(client);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING);
- ipc_client_response_free(ipc_client, &info);
+ rc = ipc_client_send(ipc_fmt_data->ipc_client, mseq, command, type, data, size);
+ if (rc < 0) {
+ RIL_LOGE("Sending to %s client failed", client->name);
+ goto error;
}
rc = 0;
goto complete;
error:
- ril_radio_state_update(RADIO_STATE_UNAVAILABLE);
- ril_sms_send(RIL_SMS_NUMBER, "Samsung-RIL: The modem just crashed, please reboot your device if you can't get service back.");
+ eventfd_send(ipc_fmt_data->event_fd, IPC_CLIENT_IO_ERROR);
rc = -1;
complete:
+ release_wake_lock(RIL_VERSION_STRING);
+ RIL_CLIENT_UNLOCK(client);
+
return rc;
}
-int ipc_fmt_create(struct ril_client *client)
+unsigned char ipc_fmt_seq(void)
{
- struct ipc_client *ipc_client;
+ struct ril_client *client;
+ struct ipc_fmt_data *data;
- int rc;
+ client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
+ if (client == NULL || client->data == NULL)
+ return 0xff;
+
+ data = (struct ipc_fmt_data *) client->data;
+ data->seq++;
+
+ if (data->seq % 0xff == 0x00)
+ data->seq = 0x01;
+
+ return data->seq;
+}
+
+unsigned char ipc_fmt_request_seq(RIL_Token token)
+{
+ struct ril_client *client;
+ struct ipc_fmt_request *request;
+
+ client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
if (client == NULL)
- return -EINVAL;
+ return 0xff;
- RIL_LOGD("Creating new FMT client");
+ request = ipc_fmt_request_find_token(client, token);
+ if (request == NULL)
+ return 0xff;
- ipc_client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
- if (ipc_client == NULL) {
- RIL_LOGE("FMT client creation failed");
- goto error_client_create;
- }
+ if (request->seq == 0xff)
+ request->seq = ipc_fmt_seq();
- client->data = (void *) ipc_client;
+ return request->seq;
+}
- RIL_LOGD("Setting log handler");
+RIL_Token ipc_fmt_request_token(unsigned char seq)
+{
+ struct ril_client *client;
+ struct ipc_fmt_request *request;
- rc = ipc_client_set_log_callback(ipc_client, ipc_log_handler, NULL);
- if (rc < 0) {
- RIL_LOGE("Setting log handler failed");
- goto error_log_callback;
- }
+ client = ril_client_find_id(RIL_CLIENT_IPC_FMT);
+ if (client == NULL)
+ return NULL;
- RIL_LOGD("Creating data");
+ request = ipc_fmt_request_find_seq(client, seq);
+ if (request == NULL)
+ return NULL;
- rc = ipc_client_data_create(ipc_client);
- if (rc < 0) {
- RIL_LOGE("Creating data failed");
- goto error_data_create;
- }
+ return request->token;
+}
- RIL_LOGD("Starting bootstrap");
+/*
+ * IPC FMT client
+ */
- rc = ipc_client_bootstrap(ipc_client);
- if (rc < 0) {
- RIL_LOGE("Modem bootstrap failed");
- goto error_bootstrap;
+int ipc_fmt_create(struct ril_client *client)
+{
+ struct ipc_fmt_data *data = NULL;
+ struct ipc_client *ipc_client = NULL;
+ int event_fd = -1;
+ int rc = 0;
+
+ if (client == NULL)
+ return -1;
+
+
+ RIL_CLIENT_LOCK(client);
+
+ client->available = 0;
+
+ data = (struct ipc_fmt_data *) calloc(1, sizeof(struct ipc_fmt_data));
+
+ event_fd = eventfd(0, EFD_NONBLOCK);
+ if (event_fd < 0) {
+ RIL_LOGE("Creating %s event failed", client->name);
+ goto error;
}
- RIL_LOGD("Client power on...");
+ data->event_fd = event_fd;
+
+ ipc_client = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+ if (ipc_client == NULL) {
+ RIL_LOGE("Creating %s client failed", client->name);
+ goto error;
+ }
- rc = ipc_client_power_on(ipc_client);
+ rc = ipc_client_data_create(ipc_client);
if (rc < 0) {
- RIL_LOGE("%s: failed to power on ipc client", __func__);
- goto error_power_on;
+ RIL_LOGE("Creating %s client data failed", client->name);
+ goto error;
}
- RIL_LOGD("Client open...");
+ rc = ipc_client_log_callback_register(ipc_client, ipc_log_handler, NULL);
+ if (rc < 0) {
+ RIL_LOGE("Setting %s client log handler failed", client->name);
+ goto error;
+ }
- rc = ipc_client_open(ipc_client);
+ rc = ipc_client_boot(ipc_client);
if (rc < 0) {
- RIL_LOGE("%s: failed to open ipc client", __func__);
- goto error_open;
+ RIL_LOGE("Booting %s client failed", client->name);
+ goto error;
}
- RIL_LOGD("IPC FMT client done");
+ data->ipc_client = ipc_client;
+ client->data = (void *) data;
- return 0;
+ rc = 0;
+ goto complete;
error:
- ipc_client_power_off(ipc_client);
+ if (event_fd >= 0)
+ close(event_fd);
-error_power_on:
-error_get_fd:
- ipc_client_close(ipc_client);
+ if (ipc_client != NULL) {
+ ipc_client_data_destroy(ipc_client);
+ ipc_client_destroy(ipc_client);
+ }
-error_open:
-error_bootstrap:
- ipc_client_data_destroy(ipc_client);
+ if (data != NULL)
+ free(data);
-error_data_create:
-error_log_callback:
- ipc_client_destroy(ipc_client);
+ rc = -1;
-error_client_create:
- client->data = NULL;
+complete:
+ RIL_CLIENT_UNLOCK(client);
- return -1;
+ return rc;
}
int ipc_fmt_destroy(struct ril_client *client)
{
- struct ipc_client *ipc_client;
+ struct ipc_fmt_data *data;
- int rc;
+ if (client == NULL || client->data == NULL)
+ return -1;
- if (client == NULL || client->data == NULL) {
- RIL_LOGE("Client was already destroyed");
- return 0;
- }
+ data = (struct ipc_fmt_data *) client->data;
- ipc_client = (struct ipc_client *) client->data;
+ if (client->available)
+ ipc_fmt_close(client);
- RIL_LOGD("Destroying ipc fmt client");
+ RIL_CLIENT_LOCK(client);
- if (ipc_client != NULL) {
- ipc_client_power_off(ipc_client);
- ipc_client_close(ipc_client);
- ipc_client_data_destroy(ipc_client);
- ipc_client_destroy(ipc_client);
+ client->available = 0;
+
+ if (data->event_fd >= 0)
+ close(data->event_fd);
+
+ if (data->ipc_client != NULL) {
+ ipc_client_data_destroy(data->ipc_client);
+ ipc_client_destroy(data->ipc_client);
}
+ RIL_CLIENT_UNLOCK(client);
+
+ ipc_fmt_flush(client);
+
+ RIL_CLIENT_LOCK(client);
+
+ memset(data, 0, sizeof(struct ipc_fmt_data));
+ free(data);
+
client->data = NULL;
+ RIL_CLIENT_UNLOCK(client);
+
return 0;
}
-/*
- * IPC RFS
- */
+int ipc_fmt_open(struct ril_client *client)
+{
+ struct ipc_fmt_data *data;
+ int rc;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+ if (data->ipc_client == NULL || data->event_fd < 0)
+ return -1;
+
+ RIL_CLIENT_LOCK(client);
+
+ if (client->failures != 1) {
+ rc = ipc_client_power_on(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Powering on %s client failed", client->name);
+ goto error;
+ }
+ }
+
+ rc = ipc_client_open(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Opening %s client failed", client->name);
+ goto error;
+ }
+
+ eventfd_flush(data->event_fd);
+
+ client->available = 1;
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ RIL_CLIENT_UNLOCK(client);
-void ipc_rfs_send(const unsigned short command, unsigned char *data, const int length, unsigned char mseq)
+ return rc;
+}
+
+int ipc_fmt_close(struct ril_client *client)
{
- struct ipc_client *ipc_client;
+ struct ipc_fmt_data *data;
+ int rc;
- if (ril_data.ipc_rfs_client == NULL || ril_data.ipc_rfs_client->data == NULL)
- return;
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+ if (data->ipc_client == NULL || data->event_fd < 0)
+ return -1;
- ipc_client = (struct ipc_client *) ril_data.ipc_rfs_client->data;
+ RIL_CLIENT_LOCK(client);
- RIL_CLIENT_LOCK(ril_data.ipc_rfs_client);
- ipc_client_send(ipc_client, command, 0, data, length, mseq);
- RIL_CLIENT_UNLOCK(ril_data.ipc_rfs_client);
+ client->available = 0;
+
+ rc = eventfd_send(data->event_fd, IPC_CLIENT_CLOSE);
+ if (rc < 0) {
+ RIL_LOGE("Sending %s close event failed", client->name);
+ goto error;
+ }
+
+ rc = ipc_client_close(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Closing %s client failed", client->name);
+ goto error;
+ }
+
+ if (client->failures != 1) {
+ rc = ipc_client_power_off(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Powering off %s client failed", client->name);
+ goto error;
+ }
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ RIL_CLIENT_UNLOCK(client);
+
+ return rc;
}
-int ipc_rfs_read_loop(struct ril_client *client)
+int ipc_fmt_dispatch(struct ril_client *client, struct ipc_message *message)
{
- struct ipc_client *ipc_client;
- struct ipc_message_info info;
+ unsigned int i;
+ int rc;
+
+ if (client == NULL || message == NULL || ril_data == NULL)
+ return -1;
+ RIL_LOCK();
+
+ for (i = 0; i < ipc_fmt_dispatch_handlers_count; i++) {
+ if (ipc_fmt_dispatch_handlers[i].handler == NULL)
+ continue;
+
+ if (ipc_fmt_dispatch_handlers[i].command == message->command) {
+ rc = ipc_fmt_dispatch_handlers[i].handler(message);
+ if (rc < 0)
+ goto error;
+
+ rc = 0;
+ goto complete;
+ }
+ }
+
+ RIL_LOGD("Unhandled %s message: %s", client->name, ipc_command_string(message->command));
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ RIL_UNLOCK();
+
+ return rc;
+}
+
+int ipc_fmt_loop(struct ril_client *client)
+{
+ struct ipc_fmt_data *data;
+ struct ipc_message message;
+ struct ipc_poll_fds fds;
+ int fds_array[] = { 0 };
+ unsigned int count;
+ eventfd_t event;
int rc;
if (client == NULL || client->data == NULL)
- return -EINVAL;
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+ if (data->ipc_client == NULL || data->event_fd < 0)
+ return -1;
+
+ memset(&fds, 0, sizeof(fds));
+ fds.fds = (int *) &fds_array;
- ipc_client = (struct ipc_client *) client->data;
+ count = sizeof(fds_array) / sizeof(int);
while (1) {
- rc = ipc_client_poll(ipc_client, NULL);
+ if (!client->available) {
+ RIL_LOGE("%s client is not available", client->name);
+ return -1;
+ }
+
+ fds_array[0] = data->event_fd;
+ fds.count = count;
+
+ rc = ipc_client_poll(data->ipc_client, &fds, NULL);
if (rc < 0) {
- RIL_LOGE("IPC RFS client poll failed, aborting");
- goto error;
+ RIL_LOGE("Polling %s client failed", client->name);
+ return -1;
}
- memset(&info, 0, sizeof(info));
+ if (fds.fds[0] == data->event_fd && fds.count > 0) {
+ rc = eventfd_recv(data->event_fd, &event);
+ if (rc < 0)
+ return -1;
+
+ switch (event) {
+ case IPC_CLIENT_CLOSE:
+ return 0;
+ case IPC_CLIENT_IO_ERROR:
+ return -1;
+ }
+ }
+
+ if ((unsigned int) rc == fds.count)
+ continue;
+
+ memset(&message, 0, sizeof(message));
+ RIL_LOCK();
RIL_CLIENT_LOCK(client);
- if (ipc_client_recv(ipc_client, &info) < 0) {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING);
+
+ rc = ipc_client_recv(data->ipc_client, &message);
+ if (rc < 0) {
+ RIL_LOGE("Receiving from %s client failed", client->name);
+
+ release_wake_lock(RIL_VERSION_STRING);
RIL_CLIENT_UNLOCK(client);
- RIL_LOGE("IPC RFS recv failed, aborting");
- goto error;
+ RIL_UNLOCK();
+
+ return -1;
}
+
+ release_wake_lock(RIL_VERSION_STRING);
RIL_CLIENT_UNLOCK(client);
+ RIL_UNLOCK();
+
+ rc = ipc_fmt_dispatch(client, &message);
+ if (rc < 0) {
+ RIL_LOGE("Dispatching %s message failed", client->name);
- ipc_rfs_dispatch(&info);
+ if (message.data != NULL && message.size > 0)
+ free(message.data);
- ipc_client_response_free(ipc_client, &info);
+ return -1;
+ }
+
+ if (client->failures)
+ client->failures = 0;
+
+ if (message.data != NULL && message.size > 0)
+ free(message.data);
+ }
+
+ return 0;
+}
+
+int ipc_fmt_request_register(struct ril_client *client, int request,
+ RIL_Token token)
+{
+ struct ipc_fmt_data *data;
+ struct ipc_fmt_request *ipc_fmt_request;
+ struct list_head *list_end;
+ struct list_head *list;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+
+ RIL_CLIENT_LOCK(client);
+
+ ipc_fmt_request = (struct ipc_fmt_request *) calloc(1, sizeof(struct ipc_fmt_request));
+ ipc_fmt_request->request = request;
+ ipc_fmt_request->token = token;
+ ipc_fmt_request->seq = 0xff;
+
+ list_end = data->requests;
+ while (list_end != NULL && list_end->next != NULL)
+ list_end = list_end->next;
+
+ list = list_head_alloc(list_end, NULL, (void *) ipc_fmt_request);
+
+ if (data->requests == NULL)
+ data->requests = list;
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return 0;
+}
+
+int ipc_fmt_request_unregister(struct ril_client *client, int request,
+ RIL_Token token)
+{
+ struct ipc_fmt_data *data;
+ struct ipc_fmt_request *ipc_fmt_request;
+ struct list_head *list;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+
+ RIL_CLIENT_LOCK(client);
+
+ list = data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ ipc_fmt_request = (struct ipc_fmt_request *) list->data;
+
+ if (ipc_fmt_request->request == request && ipc_fmt_request->token == token) {
+ memset(ipc_fmt_request, 0, sizeof(struct ipc_fmt_request));
+ free(ipc_fmt_request);
+
+ if (list == data->requests)
+ data->requests = list->next;
+
+ list_head_free(list);
+
+ break;
+ }
+
+list_continue:
+ list = list->next;
+ }
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return 0;
+}
+
+int ipc_fmt_request_flush(struct ril_client *client)
+{
+ struct ipc_fmt_data *data;
+ struct ipc_fmt_request *ipc_fmt_request;
+ struct list_head *list;
+ struct list_head *list_next;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+
+ RIL_CLIENT_LOCK(client);
+
+ list = data->requests;
+ while (list != NULL) {
+ if (list->data != NULL) {
+ ipc_fmt_request = (struct ipc_fmt_request *) list->data;
+
+ memset(ipc_fmt_request, 0, sizeof(struct ipc_fmt_request));
+ free(ipc_fmt_request);
+ }
+
+ if (list == data->requests)
+ data->requests = list->next;
+
+ list_next = list->next;
+
+ list_head_free(list);
+
+list_continue:
+ list = list_next;
+ }
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return 0;
+}
+
+struct ipc_fmt_request *ipc_fmt_request_find_token(struct ril_client *client,
+ RIL_Token token)
+{
+ struct ipc_fmt_data *data;
+ struct ipc_fmt_request *request;
+ struct list_head *list;
+
+ if (client == NULL || client->data == NULL)
+ return NULL;
+
+ data = (struct ipc_fmt_data *) client->data;
+
+ RIL_CLIENT_LOCK(client);
+
+ list = data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request = (struct ipc_fmt_request *) list->data;
+
+ if (request->token == token) {
+ RIL_CLIENT_UNLOCK(client);
+ return request;
+ }
+
+list_continue:
+ list = list->next;
+ }
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return NULL;
+}
+
+struct ipc_fmt_request *ipc_fmt_request_find_seq(struct ril_client *client,
+ unsigned char seq)
+{
+ struct ipc_fmt_data *data;
+ struct ipc_fmt_request *request;
+ struct list_head *list;
+
+ if (client == NULL || client->data == NULL)
+ return NULL;
+
+ data = (struct ipc_fmt_data *) client->data;
+
+ RIL_CLIENT_LOCK(client);
+
+ list = data->requests;
+ while (list != NULL) {
+ if (list->data == NULL)
+ goto list_continue;
+
+ request = (struct ipc_fmt_request *) list->data;
+
+ if (request->seq == seq) {
+ RIL_CLIENT_UNLOCK(client);
+ return request;
+ }
+
+list_continue:
+ list = list->next;
+ }
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return NULL;
+}
+
+int ipc_fmt_flush(struct ril_client *client)
+{
+ struct ipc_fmt_data *data;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_fmt_data *) client->data;
+
+ ipc_fmt_request_flush(client);
+
+ ipc_gen_phone_res_expect_flush(client);
+
+ RIL_CLIENT_LOCK(client);
+
+ memset(&data->sim_icc_type_data, 0, sizeof(data->sim_icc_type_data));
+ memset(&data->hsdpa_status_data, 0, sizeof(data->hsdpa_status_data));
+ data->svc_session = 0;
+
+ data->seq = 0x00;
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return 0;
+}
+/*
+ * IPC RFS
+ */
+
+int ipc_rfs_send(unsigned char mseq, unsigned short command, const void *data,
+ size_t size)
+{
+ struct ril_client *client;
+ struct ipc_rfs_data *ipc_rfs_data;
+ int rc;
+
+ client = ril_client_find_id(RIL_CLIENT_IPC_RFS);
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ ipc_rfs_data = (struct ipc_rfs_data *) client->data;
+ if (ipc_rfs_data->ipc_client == NULL || ipc_rfs_data->event_fd < 0)
+ return -1;
+
+ if (!client->available) {
+ RIL_LOGE("%s client is not available", client->name);
+ return -1;
+ }
+
+ RIL_CLIENT_LOCK(client);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING);
+
+ rc = ipc_client_send(ipc_rfs_data->ipc_client, mseq, command, 0x00, data, size);
+ if (rc < 0) {
+ RIL_LOGE("Sending to %s client failed", client->name);
+ goto error;
}
rc = 0;
goto complete;
error:
- ril_radio_state_update(RADIO_STATE_UNAVAILABLE);
- ril_sms_send(RIL_SMS_NUMBER, "Samsung-RIL: The modem just crashed, please reboot your device if you can't get service back.");
+ eventfd_send(ipc_rfs_data->event_fd, IPC_CLIENT_IO_ERROR);
rc = -1;
complete:
+ release_wake_lock(RIL_VERSION_STRING);
+ RIL_CLIENT_UNLOCK(client);
+
return rc;
}
+/*
+ * IPC RFS client
+ */
+
int ipc_rfs_create(struct ril_client *client)
{
- struct ipc_client *ipc_client;
-
- int rc;
+ struct ipc_rfs_data *data = NULL;
+ struct ipc_client *ipc_client = NULL;
+ int event_fd = -1;
+ int rc = 0;
if (client == NULL)
- return -EINVAL;
-
- RIL_LOGD("Creating new RFS client");
+ return -1;
- ipc_client = ipc_client_create(IPC_CLIENT_TYPE_RFS);
- if (ipc_client == NULL) {
- RIL_LOGE("RFS client creation failed");
- goto error_client_create;
- }
+ data = (struct ipc_rfs_data *) calloc(1, sizeof(struct ipc_rfs_data));
- client->data = (void *) ipc_client;
+ RIL_CLIENT_LOCK(client);
- RIL_LOGD("Setting log handler");
+ client->available = 0;
- rc = ipc_client_set_log_callback(ipc_client, ipc_log_handler, NULL);
- if (rc < 0) {
- RIL_LOGE("Setting log handler failed");
- goto error_log_callback;
+ event_fd = eventfd(0, EFD_NONBLOCK);
+ if (event_fd < 0) {
+ RIL_LOGE("Creating %s event failed", client->name);
+ goto error;
}
- RIL_LOGD("Creating data");
+ data->event_fd = event_fd;
+
+ ipc_client = ipc_client_create(IPC_CLIENT_TYPE_RFS);
+ if (ipc_client == NULL) {
+ RIL_LOGE("Creating %s client failed", client->name);
+ goto error;
+ }
rc = ipc_client_data_create(ipc_client);
if (rc < 0) {
- RIL_LOGE("Creating data failed");
- goto error_data_create;
+ RIL_LOGE("Creating %s client data failed", client->name);
+ goto error;
}
- RIL_LOGD("Client open...");
-
- rc = ipc_client_open(ipc_client);
+ rc = ipc_client_log_callback_register(ipc_client, ipc_log_handler, NULL);
if (rc < 0) {
- RIL_LOGE("%s: failed to open ipc client", __func__);
- goto error_open;
+ RIL_LOGE("Setting %s client log handler failed", client->name);
+ goto error;
}
- RIL_LOGD("IPC RFS client done");
+ data->ipc_client = ipc_client;
+ client->data = (void *) data;
- return 0;
+ rc = 0;
+ goto complete;
error:
-error_get_fd:
- ipc_client_close(ipc_client);
+ if (event_fd >= 0)
+ close(event_fd);
-error_open:
- ipc_client_data_destroy(ipc_client);
+ if (ipc_client != NULL) {
+ ipc_client_data_destroy(ipc_client);
+ ipc_client_destroy(ipc_client);
+ }
-error_data_create:
-error_log_callback:
- ipc_client_destroy(ipc_client);
+ if (data != NULL)
+ free(data);
-error_client_create:
- client->data = NULL;
+ rc = -1;
- return -1;
-}
+complete:
+ RIL_CLIENT_UNLOCK(client);
+ return rc;
+}
int ipc_rfs_destroy(struct ril_client *client)
{
- struct ipc_client *ipc_client;
+ struct ipc_rfs_data *data;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_rfs_data *) client->data;
+
+ if (client->available)
+ ipc_rfs_close(client);
+
+ RIL_CLIENT_LOCK(client);
+
+ client->available = 0;
+
+ if (data->event_fd >= 0)
+ close(data->event_fd);
+
+ if (data->ipc_client != NULL) {
+ ipc_client_data_destroy(data->ipc_client);
+ ipc_client_destroy(data->ipc_client);
+ }
+
+ memset(data, 0, sizeof(struct ipc_rfs_data));
+ free(data);
+
+ client->data = NULL;
+
+ RIL_CLIENT_UNLOCK(client);
+
+ return 0;
+}
+int ipc_rfs_open(struct ril_client *client)
+{
+ struct ipc_rfs_data *data;
int rc;
- if (client == NULL || client->data == NULL) {
- RIL_LOGE("Client was already destroyed");
- return 0;
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_rfs_data *) client->data;
+ if (data->ipc_client == NULL || data->event_fd < 0)
+ return -1;
+
+ RIL_CLIENT_LOCK(client);
+
+ rc = ipc_client_open(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Opening %s client failed", client->name);
+ goto error;
}
- ipc_client = (struct ipc_client *) client->data;
+ eventfd_flush(data->event_fd);
- RIL_LOGD("Destroying ipc rfs client");
+ client->available = 1;
- if (ipc_client != NULL) {
- ipc_client_close(ipc_client);
- ipc_client_data_destroy(ipc_client);
- ipc_client_destroy(ipc_client);
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ RIL_CLIENT_UNLOCK(client);
+
+ return rc;
+}
+
+int ipc_rfs_close(struct ril_client *client)
+{
+ struct ipc_rfs_data *data;
+ int rc;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_rfs_data *) client->data;
+ if (data->ipc_client == NULL || data->event_fd < 0)
+ return -1;
+
+ RIL_CLIENT_LOCK(client);
+
+ client->available = 0;
+
+ rc = eventfd_send(data->event_fd, IPC_CLIENT_CLOSE);
+ if (rc < 0) {
+ RIL_LOGE("Sending %s close event failed", client->name);
+ goto error;
}
- client->data = NULL;
+ rc = ipc_client_close(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Closing %s client failed", client->name);
+ goto error;
+ }
+
+ rc = ipc_client_power_off(data->ipc_client);
+ if (rc < 0) {
+ RIL_LOGE("Powering off %s client failed", client->name);
+ goto error;
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ RIL_CLIENT_UNLOCK(client);
+
+ return rc;
+}
+
+int ipc_rfs_dispatch(struct ril_client *client, struct ipc_message *message)
+{
+ unsigned int i;
+ int rc;
+
+ if (client == NULL || message == NULL || ril_data == NULL)
+ return -1;
+
+ RIL_LOCK();
+
+ for (i = 0; i < ipc_rfs_dispatch_handlers_count; i++) {
+ if (ipc_rfs_dispatch_handlers[i].handler == NULL)
+ continue;
+
+ if (ipc_rfs_dispatch_handlers[i].command == message->command) {
+ rc = ipc_rfs_dispatch_handlers[i].handler(message);
+ if (rc < 0)
+ goto error;
+
+ rc = 0;
+ goto complete;
+ }
+ }
+
+ RIL_LOGD("Unhandled %s message: %s", client->name, ipc_command_string(message->command));
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ RIL_UNLOCK();
+
+ return rc;
+}
+
+int ipc_rfs_loop(struct ril_client *client)
+{
+ struct ipc_rfs_data *data;
+ struct ipc_message message;
+ struct ipc_poll_fds fds;
+ int fds_array[] = { 0 };
+ unsigned int count;
+ eventfd_t event;
+ int rc;
+
+ if (client == NULL || client->data == NULL)
+ return -1;
+
+ data = (struct ipc_rfs_data *) client->data;
+ if (data->ipc_client == NULL || data->event_fd < 0)
+ return -1;
+
+ memset(&fds, 0, sizeof(fds));
+ fds.fds = (int *) &fds_array;
+
+ count = sizeof(fds_array) / sizeof(int);
+
+ while (1) {
+ if (!client->available) {
+ RIL_LOGE("%s client is not available", client->name);
+ return -1;
+ }
+
+ fds_array[0] = data->event_fd;
+ fds.count = count;
+
+ rc = ipc_client_poll(data->ipc_client, &fds, NULL);
+ if (rc < 0) {
+ RIL_LOGE("Polling %s client failed", client->name);
+ return -1;
+ }
+
+ if (fds.fds[0] == data->event_fd && fds.count > 0) {
+ rc = eventfd_recv(data->event_fd, &event);
+ if (rc < 0)
+ return -1;
+
+ switch (event) {
+ case IPC_CLIENT_CLOSE:
+ return 0;
+ case IPC_CLIENT_IO_ERROR:
+ return -1;
+ }
+ }
+
+ if ((unsigned int) rc == fds.count)
+ continue;
+
+ memset(&message, 0, sizeof(message));
+
+ RIL_LOCK();
+ RIL_CLIENT_LOCK(client);
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, RIL_VERSION_STRING);
+
+ rc = ipc_client_recv(data->ipc_client, &message);
+ if (rc < 0) {
+ RIL_LOGE("Receiving from %s client failed", client->name);
+
+ release_wake_lock(RIL_VERSION_STRING);
+ RIL_CLIENT_UNLOCK(client);
+ RIL_UNLOCK();
+
+ return -1;
+ }
+
+ release_wake_lock(RIL_VERSION_STRING);
+ RIL_CLIENT_UNLOCK(client);
+ RIL_UNLOCK();
+
+ rc = ipc_rfs_dispatch(client, &message);
+ if (rc < 0) {
+ RIL_LOGE("Dispatching %s message failed", client->name);
+
+ if (message.data != NULL && message.size > 0)
+ free(message.data);
+
+ return -1;
+ }
+
+ if (client->failures)
+ client->failures = 0;
+
+ if (message.data != NULL && message.size > 0)
+ free(message.data);
+ }
return 0;
}
/*
- * IPC clients structures
+ * RIL clients
*/
-struct ril_client_funcs ipc_fmt_client_funcs = {
+struct ril_client_handlers ipc_fmt_handlers = {
.create = ipc_fmt_create,
.destroy = ipc_fmt_destroy,
- .read_loop = ipc_fmt_read_loop,
+ .open = ipc_fmt_open,
+ .close = ipc_fmt_close,
+ .loop = ipc_fmt_loop,
};
-struct ril_client_funcs ipc_rfs_client_funcs = {
+struct ril_client_handlers ipc_rfs_handlers = {
.create = ipc_rfs_create,
.destroy = ipc_rfs_destroy,
- .read_loop = ipc_rfs_read_loop,
+ .open = ipc_rfs_open,
+ .close = ipc_rfs_close,
+ .loop = ipc_rfs_loop,
+};
+
+struct ril_client_callbacks ipc_fmt_callbacks = {
+ .request_register = ipc_fmt_request_register,
+ .request_unregister = ipc_fmt_request_unregister,
+ .flush = ipc_fmt_flush,
+};
+
+struct ril_client_callbacks ipc_rfs_callbacks = {
+ .request_register = NULL,
+ .request_unregister = NULL,
+ .flush = NULL,
+};
+
+struct ril_client ipc_fmt_client = {
+ .id = RIL_CLIENT_IPC_FMT,
+ .name = "IPC FMT",
+ .critical = 1,
+ .handlers = &ipc_fmt_handlers,
+ .callbacks = &ipc_fmt_callbacks,
+};
+
+struct ril_client ipc_rfs_client = {
+ .id = RIL_CLIENT_IPC_RFS,
+ .name = "IPC RFS",
+ .critical = 0,
+ .handlers = &ipc_rfs_handlers,
+ .callbacks = &ipc_rfs_callbacks,
};