aboutsummaryrefslogtreecommitdiffstats
path: root/samsung-ipc/devices/crespo/crespo.c
diff options
context:
space:
mode:
Diffstat (limited to 'samsung-ipc/devices/crespo/crespo.c')
-rw-r--r--samsung-ipc/devices/crespo/crespo.c564
1 files changed, 564 insertions, 0 deletions
diff --git a/samsung-ipc/devices/crespo/crespo.c b/samsung-ipc/devices/crespo/crespo.c
new file mode 100644
index 0000000..fe50012
--- /dev/null
+++ b/samsung-ipc/devices/crespo/crespo.c
@@ -0,0 +1,564 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Joerie de Gram <j.de.gram@gmail.com>
+ * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
+ * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr>
+ *
+ * libsamsung-ipc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * libsamsung-ipc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <samsung-ipc.h>
+#include <ipc.h>
+#include <utils.h>
+
+#include "crespo_modem_ctl.h"
+
+#include "xmm6160.h"
+#include "crespo.h"
+
+int crespo_boot(struct ipc_client *client)
+{
+ void *modem_image_data = NULL;
+ int modem_ctl_fd = -1;
+ int serial_fd = -1;
+ unsigned char *p;
+ int rc;
+
+ if (client == NULL)
+ return -1;
+
+ ipc_client_log(client, "Starting crespo modem boot");
+
+ modem_image_data = file_data_read(CRESPO_MODEM_IMAGE_DEVICE, CRESPO_MODEM_IMAGE_SIZE, 0x1000, 0);
+ if (modem_image_data == NULL) {
+ ipc_client_log(client, "Reading modem image data failed");
+ goto error;
+ }
+ ipc_client_log(client, "Read modem image data");
+
+ modem_ctl_fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR | O_NDELAY);
+ if (modem_ctl_fd < 0) {
+ ipc_client_log(client, "Opening modem ctl failed");
+ goto error;
+ }
+ ipc_client_log(client, "Opened modem ctl");
+
+ rc = ioctl(modem_ctl_fd, IOCTL_MODEM_RESET);
+ if (rc < 0) {
+ ipc_client_log(client, "Resetting modem failed");
+ goto error;
+ }
+ ipc_client_log(client, "Reset modem");
+
+ serial_fd = open(CRESPO_MODEM_SERIAL_DEVICE, O_RDWR | O_NDELAY);
+ if (serial_fd < 0) {
+ ipc_client_log(client, "Opening serial failed");
+ goto error;
+ }
+ ipc_client_log(client, "Opened serial");
+
+ usleep(100000);
+
+ p = (unsigned char *) modem_image_data;
+
+ rc = xmm6160_psi_send(client, serial_fd, (void *) p, CRESPO_PSI_SIZE);
+ if (rc < 0) {
+ ipc_client_log(client, "Sending XMM6160 PSI failed");
+ goto error;
+ }
+ ipc_client_log(client, "Sent XMM6160 PSI");
+
+ p += CRESPO_PSI_SIZE;
+
+ lseek(modem_ctl_fd, 0, SEEK_SET);
+
+ rc = xmm6160_firmware_send(client, modem_ctl_fd, NULL, (void *) p, CRESPO_MODEM_IMAGE_SIZE - CRESPO_PSI_SIZE);
+ if (rc < 0) {
+ ipc_client_log(client, "Sending XMM6160 firmware failed");
+ goto error;
+ }
+ ipc_client_log(client, "Sent XMM6160 firmware");
+
+ lseek(modem_ctl_fd, CRESPO_MODEM_CTL_NV_DATA_OFFSET, SEEK_SET);
+
+ rc = xmm6160_nv_data_send(client, modem_ctl_fd, NULL);
+ if (rc < 0) {
+ ipc_client_log(client, "Sending XMM6160 nv_data failed");
+ goto error;
+ }
+ ipc_client_log(client, "Sent XMM6160 nv_data");
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (modem_image_data != NULL)
+ free(modem_image_data);
+
+ if (serial_fd >= 0)
+ close(serial_fd);
+
+ if (modem_ctl_fd >= 0)
+ close(modem_ctl_fd);
+
+ return rc;
+}
+
+int crespo_fmt_send(struct ipc_client *client, struct ipc_message *message)
+{
+ struct ipc_fmt_header header;
+ struct modem_io mio;
+ int rc;
+
+ if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || message == NULL)
+ return -1;
+
+ ipc_fmt_header_setup(&header, message);
+
+ memset(&mio, 0, sizeof(struct modem_io));
+ mio.size = message->size + sizeof(struct ipc_fmt_header);
+ mio.data = calloc(1, mio.size);
+
+ memcpy(mio.data, &header, sizeof(struct ipc_fmt_header));
+ if (message->data != NULL && message->size > 0)
+ memcpy((void *) ((unsigned char *) mio.data + sizeof(struct ipc_fmt_header)), message->data, message->size);
+
+ ipc_client_log_send(client, message, __func__);
+
+ rc = client->handlers->write(client->handlers->transport_data, (void *) &mio, sizeof(struct modem_io));
+ if (rc < 0) {
+ ipc_client_log(client, "Writing FMT data failed");
+ goto error;
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (mio.data != NULL)
+ free(mio.data);
+
+ return rc;
+}
+
+int crespo_fmt_recv(struct ipc_client *client, struct ipc_message *message)
+{
+ struct ipc_fmt_header *header;
+ struct modem_io mio;
+ int rc;
+
+ if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || message == NULL)
+ return -1;
+
+ memset(&mio, 0, sizeof(struct modem_io));
+ mio.size = CRESPO_BUFFER_LENGTH;
+ mio.data = calloc(1, mio.size);
+
+ rc = client->handlers->read(client->handlers->transport_data, &mio, sizeof(struct modem_io) + mio.size);
+ if (rc < 0 || mio.data == NULL || mio.size < sizeof(struct ipc_fmt_header)) {
+ ipc_client_log(client, "Reading FMT data failed");
+ goto error;
+ }
+
+ header = (struct ipc_fmt_header *) mio.data;
+
+ ipc_fmt_message_setup(header, message);
+
+ if (mio.size > sizeof(struct ipc_fmt_header)) {
+ message->size = mio.size - sizeof(struct ipc_fmt_header);
+ message->data = calloc(1, message->size);
+
+ memcpy(message->data, (void *) ((unsigned char *) mio.data + sizeof(struct ipc_fmt_header)), message->size);
+ }
+
+ ipc_client_log_recv(client, message, __func__);
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (mio.data != NULL)
+ free(mio.data);
+
+ return rc;
+}
+
+int crespo_rfs_send(struct ipc_client *client, struct ipc_message *message)
+{
+ struct modem_io mio;
+ int rc;
+
+ if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || message == NULL)
+ return -1;
+
+ memset(&mio, 0, sizeof(struct modem_io));
+ mio.id = message->mseq;
+ mio.cmd = IPC_INDEX(message->command);
+ mio.size = message->size;
+
+ if (message->data != NULL && message->size > 0) {
+ mio.data = calloc(1, mio.size);
+
+ memcpy(mio.data, message->data, message->size);
+ }
+
+ ipc_client_log_send(client, message, __func__);
+
+ rc = client->handlers->write(client->handlers->transport_data, (void *) &mio, sizeof(struct modem_io));
+ if (rc < 0) {
+ ipc_client_log(client, "Writing RFS data failed");
+ goto error;
+ }
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (mio.data != NULL)
+ free(mio.data);
+
+ return rc;
+}
+
+int crespo_rfs_recv(struct ipc_client *client, struct ipc_message *message)
+{
+ struct modem_io mio;
+ int rc;
+
+ if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || message == NULL)
+ return -1;
+
+ memset(&mio, 0, sizeof(struct modem_io));
+ mio.size = CRESPO_BUFFER_LENGTH;
+ mio.data = calloc(1, mio.size);
+
+ rc = client->handlers->read(client->handlers->transport_data, &mio, sizeof(struct modem_io) + mio.size);
+ if (rc < 0 || mio.data == NULL || mio.size <= 0) {
+ ipc_client_log(client, "Reading RFS data failed");
+ goto error;
+ }
+
+ memset(message, 0, sizeof(struct ipc_message));
+ message->aseq = mio.id;
+ message->command = IPC_COMMAND(IPC_GROUP_RFS, mio.cmd);
+
+ if (mio.size > 0) {
+ message->size = mio.size;
+ message->data = calloc(1, message->size);
+
+ memcpy(message->data, mio.data, message->size);
+ }
+
+ ipc_client_log_recv(client, message, __func__);
+
+ rc = 0;
+ goto complete;
+
+error:
+ rc = -1;
+
+complete:
+ if (mio.data != NULL)
+ free(mio.data);
+
+ return rc;
+}
+
+int crespo_open(void *data, int type)
+{
+ struct crespo_transport_data *transport_data;
+ int fd;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct crespo_transport_data *) data;
+
+ switch (type) {
+ case IPC_CLIENT_TYPE_FMT:
+ fd = open(CRESPO_MODEM_FMT_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ break;
+ case IPC_CLIENT_TYPE_RFS:
+ fd = open(CRESPO_MODEM_RFS_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ break;
+ default:
+ return -1;
+ }
+
+ if (fd < 0)
+ return -1;
+
+ transport_data->fd = fd;
+
+ return 0;
+}
+
+int crespo_close(void *data)
+{
+ struct crespo_transport_data *transport_data;
+ int fd;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct crespo_transport_data *) data;
+
+ fd = transport_data->fd;
+ if (fd < 0)
+ return -1;
+
+ transport_data->fd = -1;
+ close(fd);
+
+ return 0;
+}
+
+int crespo_read(void *data, void *buffer, size_t length)
+{
+ struct crespo_transport_data *transport_data;
+ int fd;
+ int rc;
+
+ if (data == NULL || buffer == NULL || length == 0)
+ return -1;
+
+ transport_data = (struct crespo_transport_data *) data;
+
+ fd = transport_data->fd;
+ if (fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_RECV, buffer);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_write(void *data, const void *buffer, size_t length)
+{
+ struct crespo_transport_data *transport_data;
+ int fd;
+ int rc;
+
+ if (data == NULL || buffer == NULL || length == 0)
+ return -1;
+
+ transport_data = (struct crespo_transport_data *) data;
+
+ fd = transport_data->fd;
+ if (fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_SEND, buffer);
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_poll(void *data, struct timeval *timeout)
+{
+ struct crespo_transport_data *transport_data;
+ fd_set fds;
+ int fd;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct crespo_transport_data *) data;
+
+ fd = transport_data->fd;
+ if (fd < 0)
+ return -1;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ rc = select(fd + 1, &fds, NULL, NULL, timeout);
+ return rc;
+}
+
+int crespo_power_on(void *data)
+{
+ int fd;
+ int rc;
+
+ fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_START);
+
+ close(fd);
+
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_power_off(void *data)
+{
+ int fd;
+ int rc;
+
+ fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_OFF);
+
+ close(fd);
+
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_data_create(void **transport_data, void **power_data,
+ void **gprs_data)
+{
+ if (transport_data == NULL)
+ return -1;
+
+ *transport_data = calloc(1, sizeof(struct crespo_transport_data));
+
+ return 0;
+}
+
+int crespo_data_destroy(void *transport_data, void *power_data, void *gprs_data)
+{
+ if (transport_data == NULL)
+ return -1;
+
+ free(transport_data);
+
+ return 0;
+}
+
+char *crespo_gprs_get_iface_single(int cid)
+{
+ char *iface = NULL;
+
+ asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, 0);
+
+ return iface;
+}
+
+int crespo_gprs_get_capabilities_single(struct ipc_client_gprs_capabilities *capabilities)
+{
+ if (capabilities == NULL)
+ return -1;
+
+ capabilities->cid_count = 1;
+
+ return 0;
+}
+
+char *crespo_gprs_get_iface(int cid)
+{
+ char *iface = NULL;
+
+ if (cid > CRESPO_GPRS_IFACE_COUNT)
+ return NULL;
+
+ asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, cid - 1);
+
+ return iface;
+}
+
+int crespo_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities)
+{
+ if (capabilities == NULL)
+ return -1;
+
+ capabilities->cid_count = CRESPO_GPRS_IFACE_COUNT;
+
+ return 0;
+}
+
+struct ipc_client_ops crespo_fmt_ops = {
+ .boot = crespo_boot,
+ .send = crespo_fmt_send,
+ .recv = crespo_fmt_recv,
+};
+
+struct ipc_client_ops crespo_rfs_ops = {
+ .boot = NULL,
+ .send = crespo_rfs_send,
+ .recv = crespo_rfs_recv,
+};
+
+struct ipc_client_handlers crespo_handlers = {
+ .open = crespo_open,
+ .close = crespo_close,
+ .read = crespo_read,
+ .write = crespo_write,
+ .poll = crespo_poll,
+ .transport_data = NULL,
+ .power_on = crespo_power_on,
+ .power_off = crespo_power_off,
+ .power_data = NULL,
+ .gprs_activate = NULL,
+ .gprs_deactivate = NULL,
+ .gprs_data = NULL,
+ .data_create = crespo_data_create,
+ .data_destroy = crespo_data_destroy,
+};
+
+struct ipc_client_gprs_specs crespo_gprs_specs_single = {
+ .gprs_get_iface = crespo_gprs_get_iface_single,
+ .gprs_get_capabilities = crespo_gprs_get_capabilities_single,
+};
+
+struct ipc_client_gprs_specs crespo_gprs_specs = {
+ .gprs_get_iface = crespo_gprs_get_iface,
+ .gprs_get_capabilities = crespo_gprs_get_capabilities,
+};
+
+struct ipc_client_nv_data_specs crespo_nv_data_specs = {
+ .nv_data_path = XMM6160_NV_DATA_PATH,
+ .nv_data_md5_path = XMM6160_NV_DATA_MD5_PATH,
+ .nv_data_backup_path = XMM6160_NV_DATA_BACKUP_PATH,
+ .nv_data_backup_md5_path = XMM6160_NV_DATA_BACKUP_MD5_PATH,
+ .nv_data_secret = XMM6160_NV_DATA_SECRET,
+ .nv_data_size = XMM6160_NV_DATA_SIZE,
+ .nv_data_chunk_size = XMM6160_NV_DATA_CHUNK_SIZE,
+};
+
+// vim:ts=4:sw=4:expandtab