aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk5
-rw-r--r--samsung-ipc/Makefile.am2
-rw-r--r--samsung-ipc/devices/herolte/herolte.c664
-rw-r--r--samsung-ipc/devices/herolte/herolte.h35
-rw-r--r--samsung-ipc/devices/ipc_devices.c10
-rw-r--r--samsung-ipc/devices/ipc_devices.h1
6 files changed, 717 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index 048a212..adaf0d4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,6 +25,10 @@ ifneq (,$(filter crespo,$(TARGET_DEVICE)))
ipc_device_name := crespo
endif
+ifneq (,$(filter herolte,$(TARGET_DEVICE)))
+ ipc_device_name := herolte
+endif
+
ifneq (,$(filter i9100 galaxys2 n7000,$(TARGET_DEVICE)))
ipc_device_name := galaxys2
endif
@@ -66,6 +70,7 @@ libsamsung_ipc_local_src_files := \
samsung-ipc/devices/aries/aries.c \
samsung-ipc/devices/crespo/crespo.c \
samsung-ipc/devices/galaxys2/galaxys2.c \
+ samsung-ipc/devices/herolte/herolte.c \
samsung-ipc/devices/i9300/i9300.c \
samsung-ipc/devices/maguro/maguro.c \
samsung-ipc/devices/n5100/n5100.c \
diff --git a/samsung-ipc/Makefile.am b/samsung-ipc/Makefile.am
index 87becdd..fd865f5 100644
--- a/samsung-ipc/Makefile.am
+++ b/samsung-ipc/Makefile.am
@@ -52,6 +52,8 @@ libsamsung_ipc_la_SOURCES = \
devices/n7100/n7100.h \
devices/n5100/n5100.c \
devices/n5100/n5100.h \
+ devices/herolte/herolte.c \
+ devices/herolte/herolte.h \
utils.c \
call.c \
sms.c \
diff --git a/samsung-ipc/devices/herolte/herolte.c b/samsung-ipc/devices/herolte/herolte.c
new file mode 100644
index 0000000..509c3b1
--- /dev/null
+++ b/samsung-ipc/devices/herolte/herolte.c
@@ -0,0 +1,664 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ *
+ * 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 <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "devices/herolte/herolte.h"
+#include "ipc.h"
+#include "modems/xmm626/xmm626.h"
+#include "modems/xmm626/xmm626_kernel_smdk4412.h"
+#include "modems/xmm626/xmm626_modem_prj.h"
+
+struct __attribute__((__packed__)) firmware_toc_entry {
+ char name[12];
+ uint32_t offset; /* offset within firmware file/partition */
+ uint32_t loadaddr; /* target memory address for this blob */
+ uint32_t size; /* size of this blob in bytes */
+ uint32_t crc;
+ uint32_t entryid;
+};
+
+struct __attribute__((__packed__)) security_req {
+ uint32_t mode;
+ uint32_t size_boot;
+ uint32_t size_main;
+ uint32_t pad_zero;
+};
+
+struct __attribute__((__packed__)) modem_firmware_partition_data {
+ uint8_t *binary;
+ uint32_t size;
+ uint32_t m_offset;
+ uint32_t b_offset;
+ uint32_t mode;
+ ssize_t len;
+};
+
+#define IOCTL_SECURITY_REQ _IO('o', 0x53)
+
+#define N_TOC_ENTRIES (512 / sizeof(struct firmware_toc_entry))
+
+static struct firmware_toc_entry const *find_toc_entry(
+ char const *name,
+ struct firmware_toc_entry const *toc)
+{
+ unsigned int index;
+
+ /* We don't know all the details of the TOC format yet; for now, we
+ * assume two things:
+ * 1. reading 512 bytes of TOC is enough, and
+ * 2. the first entry with an empty name field ends the list.
+ */
+ for (index = 0; index < N_TOC_ENTRIES; index++) {
+ if (toc[index].name[0] == '\0')
+ break;
+ if (strncmp(toc[index].name, name,
+ sizeof(toc[index].name)) == 0)
+ return &toc[index];
+ }
+ return NULL;
+}
+
+#define MAX_CHUNK_LEN (62 * 1024) /* This is just what cbd uses.
+ * Perhaps a larger value would also work.
+ */
+
+static int upload_chunk(struct ipc_client *client,
+ int device_fd,
+ int firmware_fd,
+ struct firmware_toc_entry const *toc,
+ char const *name,
+ uint32_t *size)
+{
+ int rc = -1;
+ struct modem_firmware_partition_data partition;
+ struct firmware_toc_entry const *boot_toc_entry;
+ struct firmware_toc_entry const *current_toc_entry;
+ uint32_t remaining;
+
+ ipc_client_log(client, "Uploading %s", name);
+
+ boot_toc_entry = find_toc_entry("BOOT", toc);
+ if (boot_toc_entry == NULL) {
+ ipc_client_log(client,
+ "%s: Failed to find BOOT entry in the TOC",
+ __func__);
+ goto exit;
+ }
+
+ current_toc_entry = find_toc_entry(name, toc);
+ if (current_toc_entry == NULL) {
+ ipc_client_log(client, "%s: Failed to find %s entry in the TOC",
+ __func__, name);
+ goto exit;
+ }
+
+ if (size != NULL)
+ *size = current_toc_entry->size;
+ ipc_client_log(client, " - blob size for %s is %lu", name,
+ current_toc_entry->size);
+
+ partition.binary = calloc(1, MAX_CHUNK_LEN);
+ if (partition.binary == NULL) {
+ rc = -errno;
+ ipc_client_log(client, "%s: calloc failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ partition.size = current_toc_entry->size;
+ partition.m_offset = current_toc_entry->loadaddr -
+ boot_toc_entry->loadaddr;
+ partition.b_offset = current_toc_entry->offset;
+ partition.mode = 0;
+ partition.len = 0;
+
+ if (lseek(firmware_fd, partition.b_offset, SEEK_SET) < 0) {
+ rc = -errno;
+ ipc_client_log(client, "%s: lseek failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ remaining = partition.size;
+ while (remaining > 0) {
+ partition.len = remaining < MAX_CHUNK_LEN ?
+ remaining : MAX_CHUNK_LEN;
+ if (data_read(client, firmware_fd, partition.binary,
+ partition.len) != partition.len) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ if (ioctl(device_fd, IOCTL_DPRAM_SEND_BOOT, &partition) == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: IOCTL_DPRAM_SEND_BOOT failed"
+ " with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ partition.m_offset += partition.len;
+ partition.b_offset += partition.len;
+ remaining -= partition.len;
+ }
+
+ rc = 0;
+
+exit:
+ if (partition.binary != NULL) {
+ partition.binary = NULL;
+ free(partition.binary);
+ }
+
+ return rc;
+}
+
+static int select_secure_mode(struct ipc_client *client,
+ int boot0_fd,
+ int secure,
+ uint32_t size_boot,
+ uint32_t size_main)
+{
+ struct security_req req;
+ int rc;
+
+ ipc_client_log(client,
+ "Issuing IOCTL_SECURITY_REQ - setting %s mode",
+ secure ? "secure" : "insecure");
+
+ req.mode = secure ? 0 : 2;
+ req.size_boot = size_boot;
+ req.size_main = size_main;
+ req.pad_zero = 0;
+
+ if (ioctl(boot0_fd, IOCTL_SECURITY_REQ, &req) == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: "
+ "IOCTL_SECURITY_REQ failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ return -1;
+ }
+
+ return 0;
+}
+
+static char const * const modem_image_devices[] = {
+ "/dev/disk/by-partlabel/RADIO", /* PostmarketOS */
+ "/dev/block/platform/155a0000.ufs/by-name/RADIO", /* LineageOS */
+ NULL
+};
+
+static int open_image_device(struct ipc_client *client)
+{
+ int i;
+
+ for (i = 0; modem_image_devices[i] != NULL; i++) {
+ char const * const path = modem_image_devices[i];
+ int fd;
+
+ ipc_client_log(client, "Trying device path %s", path);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ if (errno == ENOENT)
+ continue;
+ /* Normally errno should be passed to the caller here */
+ return -1;
+ }
+ return fd;
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+int herolte_boot(struct ipc_client *client)
+{
+ struct firmware_toc_entry toc[N_TOC_ENTRIES];
+ int boot0_fd = -1;
+ int imagefd = -1;
+ int nvfd = -1;
+ int rc = -1;
+ uint32_t size_boot;
+ uint32_t size_main;
+
+ ipc_client_log(client, "Loading firmware TOC");
+
+ imagefd = open_image_device(client);
+ if (imagefd == -1) {
+ rc = errno;
+ if (rc == ENOENT)
+ ipc_client_log(client,
+ "%s: no modem image block device found!",
+ __func__);
+ else
+ ipc_client_log(client,
+ "%s: "
+ "open_image_device failed with error %d:"
+ " %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ if (data_read(client, imagefd, &toc[0], sizeof(toc)) != sizeof(toc)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read modem image block device failed "
+ " with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ ipc_client_log(client, "Loaded firmware TOC");
+
+ nvfd = open(herolte_nv_data_specs.nv_data_path, O_RDONLY | O_NOCTTY);
+ if (nvfd == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: opening %s failed with error %d: %s",
+ __func__, herolte_nv_data_specs.nv_data_path,
+ rc, strerror(rc));
+ goto exit;
+ }
+ ipc_client_log(client, "Opened NV data file");
+
+ boot0_fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY);
+ if (boot0_fd < 0) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: opening %s failed with error %d: %s",
+ __func__, XMM626_SEC_MODEM_BOOT0_DEVICE,
+ rc, strerror(rc));
+ goto exit;
+ }
+
+ ipc_client_log(client, "Resetting modem");
+ if (ioctl(boot0_fd, IOCTL_MODEM_RESET, 0) == -1) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: "
+ "IOCTL_MODEM_RESET failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ if (select_secure_mode(client, boot0_fd, 0, 0, 0) < 0)
+ goto exit;
+
+ if (upload_chunk(client, boot0_fd, imagefd, toc, "BOOT",
+ &size_boot) < 0)
+ goto exit;
+
+ if (upload_chunk(client, boot0_fd, imagefd, toc, "MAIN",
+ &size_main) < 0)
+ goto exit;
+
+ if (upload_chunk(client, boot0_fd, nvfd, toc, "NV", NULL) < 0)
+ goto exit;
+
+ if (select_secure_mode(client, boot0_fd, 1, size_boot, size_main) < 0)
+ goto exit;
+
+ ipc_client_log(client, "Powering on modem");
+ if (xmm626_kernel_smdk4412_power(client, boot0_fd, 1) == -1) {
+ ipc_client_log(client, "%s: Powering on modem failed",
+ __func__);
+ goto exit;
+ }
+
+ ipc_client_log(client, "Starting modem boot process");
+ if (xmm626_kernel_smdk4412_boot_power(client, boot0_fd, 1) == -1) {
+ ipc_client_log(client, "%s: Starting modem boot process failed",
+ __func__);
+ goto exit;
+ }
+
+ ipc_client_log(client, "Kicking off firmware download");
+ if (ioctl(boot0_fd, IOCTL_MODEM_DL_START, 0) < 0) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: "
+ "IOCTL_MODEM_RESET failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+
+ ipc_client_log(client, "Handshaking with modem");
+ /* At this point, cbd engages in a little dance with the
+ * newly-booted modem, apparently to verify that it is running
+ * as expected. I don’t know the sources of these magic
+ * numbers, I just faithfully reproduce them.
+ */
+ {
+ uint32_t buf;
+
+ buf = 0x900d;
+ if (data_write(client, boot0_fd, &buf, sizeof(buf)) !=
+ sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: write failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (data_read(client, boot0_fd, &buf, sizeof(buf)) !=
+ sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (buf != 0xa00d) {
+ ipc_client_log(client,
+ "%s: Handshake stage I failed: "
+ "expected 0xa00d, got 0x%x instead",
+ __func__, buf);
+ goto exit;
+ }
+ ipc_client_log(client, "Handshake stage I passed");
+
+ buf = 0x9f00;
+ if (data_write(client, boot0_fd, &buf,
+ sizeof(buf)) != sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: write failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (data_read(client, boot0_fd, &buf,
+ sizeof(buf)) != sizeof(buf)) {
+ rc = errno;
+ ipc_client_log(client,
+ "%s: read failed with error %d: %s",
+ __func__, rc, strerror(rc));
+ goto exit;
+ }
+ if (buf != 0xaf00) {
+ ipc_client_log(client,
+ "%s: Handshake stage II failed: "
+ "expected 0xaf00, got 0x%x instead",
+ __func__, buf);
+ goto exit;
+ }
+ ipc_client_log(client, "Handshake stage II passed");
+ }
+
+ ipc_client_log(client, "Finishing modem boot process");
+ if (xmm626_kernel_smdk4412_boot_power(client, boot0_fd, 0) == -1) {
+ ipc_client_log(client,
+ "%s: xmm626_kernel_smdk4412_boot_power failed",
+ __func__);
+ goto exit;
+ }
+
+ ipc_client_log(client, "Modem boot complete");
+ rc = 0;
+
+ /* Samsung's official daemons continue to read from umts_boot0
+ * (XMM626_SEC_MODEM_BOOT0_DEVICE) at this point. It may be
+ * done to restart the modem in case of errors. The fact that
+ * I have never seen anything actually come out of umts_boot0
+ * after booting is complete with libsamsung-ipc seem to be
+ * consistent with that hypothesis. With libsamsung-ipc,
+ * it's up to the daemon using it (like libsamsung-ril) to restart
+ * the boot sequence if .poll (here herolte_poll) fails.
+ * For that to work, the kernel driver needs to return an error
+ * if the modem crash for instance.
+ */
+
+ /* The kernel modem driver for this device[1] checks if both the FMT
+ * and the RFS channels are open (in the rild_ready function) and will
+ * refuse to work if both channels aren't open. Note that even if
+ * libsamsung-ipc opens both channels, at the time of writing, none
+ * of the tools in tools/ opens the RFS channel.
+ *
+ * [1]See the rild_ready function and its usage in
+ * drivers/misc/modem_v1/link_device_shmem.c in the lineage-17.0 branch
+ * https://github.com/ivanmeler/android_kernel_samsung_herolte
+ */
+
+exit:
+ if (boot0_fd != -1)
+ close(boot0_fd);
+ if (imagefd != -1)
+ close(imagefd);
+ if (nvfd != -1)
+ close(nvfd);
+ return rc;
+}
+
+int herolte_open(__attribute__((unused)) struct ipc_client *client, void *data,
+ int type)
+{
+ struct herolte_transport_data *transport_data;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ transport_data->fd = xmm626_kernel_smdk4412_open(client, type);
+ if (transport_data->fd < 0)
+ return -1;
+
+ return 0;
+}
+
+int herolte_close(__attribute__((unused)) struct ipc_client *client, void *data)
+{
+ struct herolte_transport_data *transport_data;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ xmm626_kernel_smdk4412_close(client, transport_data->fd);
+ transport_data->fd = -1;
+
+ return 0;
+}
+
+int herolte_read(__attribute__((unused)) struct ipc_client *client, void *data,
+ void *buffer, size_t length)
+{
+ struct herolte_transport_data *transport_data;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ rc = xmm626_kernel_smdk4412_read(client, transport_data->fd, buffer,
+ length);
+
+ return rc;
+}
+
+int herolte_write(__attribute__((unused)) struct ipc_client *client, void *data,
+ const void *buffer, size_t length)
+{
+ struct herolte_transport_data *transport_data;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ rc = xmm626_kernel_smdk4412_write(client, transport_data->fd, buffer,
+ length);
+
+ return rc;
+}
+
+int herolte_poll(__attribute__((unused)) struct ipc_client *client, void *data,
+ struct ipc_poll_fds *fds, struct timeval *timeout)
+{
+ struct herolte_transport_data *transport_data;
+ int rc;
+
+ if (data == NULL)
+ return -1;
+
+ transport_data = (struct herolte_transport_data *) data;
+
+ rc = xmm626_kernel_smdk4412_poll(client, transport_data->fd, fds,
+ timeout);
+
+ return rc;
+}
+
+int herolte_power_on(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data)
+{
+ return 0;
+}
+
+int herolte_power_off(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data)
+{
+ int fd;
+ int rc;
+
+ fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY |
+ O_NONBLOCK);
+ if (fd < 0)
+ return -1;
+
+ rc = xmm626_kernel_smdk4412_power(client, fd, 0);
+
+ close(fd);
+
+ if (rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int herolte_gprs_activate(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data,
+ __attribute__((unused)) unsigned int cid)
+{
+ /* TODO: For now, we don't have enough information to
+ * implement this sensibly, hence this placeholder.
+ */
+
+ return 0;
+}
+
+int herolte_gprs_deactivate(__attribute__((unused)) struct ipc_client *client,
+ __attribute__((unused)) void *data,
+ __attribute__((unused)) unsigned int cid)
+{
+ /* TODO: For now, we don't have enough information to
+ * implement this sensibly, hence this placeholder.
+ */
+
+ return 0;
+}
+
+int herolte_data_create(__attribute__((unused)) struct ipc_client *client,
+ void **transport_data,
+ __attribute__((unused)) void **power_data,
+ __attribute__((unused)) void **gprs_data)
+{
+ if (transport_data == NULL)
+ return -1;
+
+ *transport_data = calloc(1, sizeof(struct herolte_transport_data));
+
+ return 0;
+}
+
+int herolte_data_destroy(__attribute__((unused)) struct ipc_client *client,
+ void *transport_data,
+ __attribute__((unused)) void *power_data,
+ __attribute__((unused)) void *gprs_data)
+{
+ if (transport_data == NULL)
+ return -1;
+
+ free(transport_data);
+
+ return 0;
+}
+
+struct ipc_client_ops herolte_fmt_ops = {
+ .boot = herolte_boot,
+ .send = xmm626_kernel_smdk4412_fmt_send,
+ .recv = xmm626_kernel_smdk4412_fmt_recv,
+};
+
+struct ipc_client_ops herolte_rfs_ops = {
+ .boot = NULL,
+ .send = xmm626_kernel_smdk4412_rfs_send,
+ .recv = xmm626_kernel_smdk4412_rfs_recv,
+};
+
+struct ipc_client_handlers herolte_handlers = {
+ .read = herolte_read,
+ .write = herolte_write,
+ .open = herolte_open,
+ .close = herolte_close,
+ .poll = herolte_poll,
+ .transport_data = NULL,
+ .power_on = herolte_power_on,
+ .power_off = herolte_power_off,
+ .power_data = NULL,
+ .gprs_activate = herolte_gprs_activate,
+ .gprs_deactivate = herolte_gprs_deactivate,
+ .gprs_data = NULL,
+ .data_create = herolte_data_create,
+ .data_destroy = herolte_data_destroy,
+};
+
+struct ipc_client_gprs_specs herolte_gprs_specs = {
+ .gprs_get_iface = xmm626_kernel_smdk4412_gprs_get_iface,
+ .gprs_get_capabilities = xmm626_kernel_smdk4412_gprs_get_capabilities,
+};
+
+struct ipc_client_nv_data_specs herolte_nv_data_specs = {
+ .nv_data_path = XMM626_NV_DATA_PATH,
+ .nv_data_md5_path = XMM626_NV_DATA_MD5_PATH,
+ .nv_data_backup_path = XMM626_NV_DATA_BACKUP_PATH,
+ .nv_data_backup_md5_path = XMM626_NV_DATA_BACKUP_MD5_PATH,
+ .nv_data_secret = XMM626_NV_DATA_SECRET,
+ .nv_data_size = XMM626_NV_DATA_SIZE,
+ .nv_data_chunk_size = XMM626_NV_DATA_CHUNK_SIZE,
+};
diff --git a/samsung-ipc/devices/herolte/herolte.h b/samsung-ipc/devices/herolte/herolte.h
new file mode 100644
index 0000000..32d1638
--- /dev/null
+++ b/samsung-ipc/devices/herolte/herolte.h
@@ -0,0 +1,35 @@
+/*
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 2017 Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
+ * Copyright (C) 2020 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
+ *
+ * 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/>.
+ */
+
+#ifndef __HEROLTE_H__
+#define __HEROLTE_H__
+
+struct herolte_transport_data {
+ int fd;
+};
+
+extern struct ipc_client_ops herolte_fmt_ops;
+extern struct ipc_client_ops herolte_rfs_ops;
+extern struct ipc_client_handlers herolte_handlers;
+extern struct ipc_client_gprs_specs herolte_gprs_specs;
+extern struct ipc_client_nv_data_specs herolte_nv_data_specs;
+
+#endif /* __HEROLTE_H__ */
diff --git a/samsung-ipc/devices/ipc_devices.c b/samsung-ipc/devices/ipc_devices.c
index 91663f6..a0fe955 100644
--- a/samsung-ipc/devices/ipc_devices.c
+++ b/samsung-ipc/devices/ipc_devices.c
@@ -154,6 +154,16 @@ struct ipc_device_desc ipc_devices[] = {
.gprs_specs = &n5100_gprs_specs,
.nv_data_specs = &n5100_nv_data_specs,
},
+ {
+ .name = "herolte",
+ .board_name = NULL,
+ .kernel_version = NULL,
+ .fmt_ops = &herolte_fmt_ops,
+ .rfs_ops = &herolte_rfs_ops,
+ .handlers = &herolte_handlers,
+ .gprs_specs = &herolte_gprs_specs,
+ .nv_data_specs = &herolte_nv_data_specs,
+ },
};
unsigned int ipc_devices_count = sizeof(ipc_devices) /
diff --git a/samsung-ipc/devices/ipc_devices.h b/samsung-ipc/devices/ipc_devices.h
index 803a9b4..8160ee1 100644
--- a/samsung-ipc/devices/ipc_devices.h
+++ b/samsung-ipc/devices/ipc_devices.h
@@ -23,6 +23,7 @@
#include "devices/aries/aries.h"
#include "devices/crespo/crespo.h"
#include "devices/galaxys2/galaxys2.h"
+#include "devices/herolte/herolte.h"
#include "devices/i9300/i9300.h"
#include "devices/maguro/maguro.h"
#include "devices/n5100/n5100.h"