diff options
author | Paul Kocialkowski <contact@paulk.fr> | 2014-08-07 13:12:15 +0200 |
---|---|---|
committer | Paul Kocialkowski <contact@paulk.fr> | 2014-08-07 13:12:15 +0200 |
commit | a7ff1df1869ce543171a6ee92cbf821647b1bf7d (patch) | |
tree | 659e315b3d609f0f9e661d4de21b52077e6e2b81 /ipc.c | |
parent | c8408cd2c116b0b99a399282032b6607a1318b84 (diff) | |
download | hardware_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.c | 1106 |
1 files changed, 917 insertions, 189 deletions
@@ -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, }; |