aboutsummaryrefslogtreecommitdiffstats
path: root/samsung-ipc/device
diff options
context:
space:
mode:
authorJoerie de Gram <j.de.gram@gmail.com>2011-10-28 13:38:23 +0200
committerJoerie de Gram <j.de.gram@gmail.com>2011-10-28 13:53:28 +0200
commit2b9aa23db0b9c0f395abca551414a3c3ecb6d63d (patch)
tree4a3c066a2f21692cde8f5ce70ef0cc88801a7d72 /samsung-ipc/device
parent90b3b7de324debfec19829bcd77df5d8b8fba381 (diff)
downloadexternal_libsamsung-ipc-2b9aa23db0b9c0f395abca551414a3c3ecb6d63d.zip
external_libsamsung-ipc-2b9aa23db0b9c0f395abca551414a3c3ecb6d63d.tar.gz
external_libsamsung-ipc-2b9aa23db0b9c0f395abca551414a3c3ecb6d63d.tar.bz2
split devices, require compile-time device selection
Diffstat (limited to 'samsung-ipc/device')
-rw-r--r--samsung-ipc/device/crespo/crespo_ipc.c575
-rw-r--r--samsung-ipc/device/crespo/crespo_ipc.h50
-rw-r--r--samsung-ipc/device/crespo/crespo_modem_ctl.h44
-rw-r--r--samsung-ipc/device/crespo/crespo_nv_data.c353
-rw-r--r--samsung-ipc/device/crespo/crespo_nv_data.h37
-rw-r--r--samsung-ipc/device/h1/h1_ipc.c169
-rw-r--r--samsung-ipc/device/h1/h1_ipc.h44
7 files changed, 1272 insertions, 0 deletions
diff --git a/samsung-ipc/device/crespo/crespo_ipc.c b/samsung-ipc/device/crespo/crespo_ipc.c
new file mode 100644
index 0000000..cce64eb
--- /dev/null
+++ b/samsung-ipc/device/crespo/crespo_ipc.c
@@ -0,0 +1,575 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Paul Kocialkowski <contact@paulk.fr>
+ * Joerie de Gram <j.de.gram@gmail.com>
+ * Simon Busch <morphis@gravedo.de>
+ *
+ * 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 3 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <mtd/mtd-abi.h>
+#include <assert.h>
+
+#include <radio.h>
+
+#include "crespo_modem_ctl.h"
+#include "crespo_nv_data.h"
+#include "crespo_ipc.h"
+#include "ipc_private.h"
+
+int wake_lock_fd= -1;
+int wake_unlock_fd= -1;
+
+int crespo_modem_bootstrap(struct ipc_client *client)
+{
+ int s3c2410_serial3_fd= -1;
+ int modem_ctl_fd= -1;
+
+ /* Control variables. */
+ int boot_tries_count=0;
+ int rc=0;
+
+ /* Boot variables */
+ uint8_t *radio_img_p=NULL;
+ uint8_t bootcore_version=0;
+ uint8_t info_size=0;
+ uint8_t crc_byte=0;
+ int block_size=0;
+
+ /* s3c2410 serial setup variables. */
+ struct termios termios;
+ int serial;
+
+ /* fds maniplation variables */
+ struct timeval timeout;
+ fd_set fds;
+
+ /* nv_data variables */
+ void *nv_data_p;
+
+ /* General purpose variables. */
+ uint8_t data;
+ uint16_t data_16;
+ uint8_t *data_p;
+ int i;
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: enter");
+
+boot_loop_start:
+ if(boot_tries_count > 5)
+ {
+ ipc_client_log(client, "crespo_ipc_bootstrap: boot has failed too many times.");
+ goto error;
+ }
+
+ /* Read the radio.img image. */
+ ipc_client_log(client, "crespo_ipc_bootstrap: reading radio image");
+ radio_img_p=mtd_read("/dev/mtd/mtd5ro", RADIO_IMG_SIZE, 0x1000);
+ if (radio_img_p == NULL) {
+ radio_img_p = mtd_read("/dev/mtd5ro", RADIO_IMG_SIZE, 0x1000);
+ if (radio_img_p == NULL)
+ goto error;
+ }
+ ipc_client_log(client, "crespo_ipc_bootstrap: radio image read");
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: open modem_ctl");
+ modem_ctl_fd=open("/dev/modem_ctl", O_RDWR | O_NDELAY);
+ if(modem_ctl_fd < 0)
+ goto error_loop;
+
+ /* Reset the modem before init to send the first part of modem.img. */
+ ioctl(modem_ctl_fd, IOCTL_MODEM_RESET);
+ usleep(400000);
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: open s3c2410_serial3");
+ s3c2410_serial3_fd=open("/dev/s3c2410_serial3", O_RDWR | O_NDELAY);
+ if(s3c2410_serial3_fd < 0)
+ goto error_loop;
+
+ /* Setup the s3c2410 serial. */
+ ipc_client_log(client, "crespo_ipc_bootstrap: setup s3c2410_serial3");
+ tcgetattr(s3c2410_serial3_fd, &termios);
+
+ cfmakeraw(&termios);
+ cfsetispeed(&termios, B115200);
+ cfsetospeed(&termios, B115200);
+
+ tcsetattr(s3c2410_serial3_fd, TCSANOW, &termios);
+
+ ioctl(s3c2410_serial3_fd, TIOCMGET, &serial); //FIXME
+ ioctl(s3c2410_serial3_fd, TIOCMSET, &serial); //FIXME
+
+ tcgetattr(s3c2410_serial3_fd, &termios); //FIXME
+ tcsetattr(s3c2410_serial3_fd, TCSANOW, &termios); //FIXME
+
+ /* Send 'AT' in ASCII. */
+ ipc_client_log(client, "crespo_ipc_bootstrap: sending AT in ASCII");
+ for(i=0 ; i < 20 ; i++)
+ {
+ rc = write(s3c2410_serial3_fd, "AT", 2);
+ usleep(50000);
+ }
+ ipc_client_log(client, "crespo_ipc_bootstrap: sending AT in ASCII done");
+
+ usleep(50000); //FIXME
+
+ /* Get and check bootcore version. */
+ read(s3c2410_serial3_fd, &bootcore_version, sizeof(bootcore_version));
+ ipc_client_log(client, "crespo_ipc_bootstrap: got bootcore version: 0x%x", bootcore_version);
+
+ if(bootcore_version != BOOTCORE_VERSION)
+ goto error_loop;
+
+ /* Get info_size. */
+ read(s3c2410_serial3_fd, &info_size, sizeof(info_size));
+ ipc_client_log(client, "crespo_ipc_bootstrap: got info_size: 0x%x", info_size);
+
+ /* Send PSI magic. */
+ data=PSI_MAGIC;
+ write(s3c2410_serial3_fd, &data, sizeof(data));
+ ipc_client_log(client, "crespo_ipc_bootstrap: sent PSI_MAGIC (0x%x)", PSI_MAGIC);
+
+ /* Send PSI data len. */
+ data_16=PSI_DATA_LEN;
+ data_p=(uint8_t *)&data_16;
+
+ for(i=0 ; i < 2 ; i++)
+ {
+ write(s3c2410_serial3_fd, data_p, 1);
+ data_p++;
+ }
+ ipc_client_log(client, "crespo_ipc_bootstrap: sent PSI_DATA_LEN (0x%x)", PSI_DATA_LEN);
+
+ /* Write the first part of modem.img. */
+ FD_ZERO(&fds);
+ FD_SET(s3c2410_serial3_fd, &fds);
+
+ timeout.tv_sec=4;
+ timeout.tv_usec=0;
+
+ data_p=radio_img_p;
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: sending the first part of radio.img");
+
+ for(i=0 ; i < PSI_DATA_LEN ; i++)
+ {
+ if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0)
+ {
+ ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed");
+ goto error_loop;
+ }
+
+ write(s3c2410_serial3_fd, data_p, 1);
+ crc_byte=crc_byte ^ *data_p;
+
+ data_p++;
+ }
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: first part of radio.img sent; crc_byte is 0x%x", crc_byte);
+
+ if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0)
+ {
+ ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed");
+ goto error_loop;
+ }
+
+ write(s3c2410_serial3_fd, &crc_byte, sizeof(crc_byte));
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: crc_byte sent");
+
+ data = 0;
+ for(i = 0 ; data != 0x01 ; i++)
+ {
+ if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0)
+ {
+ ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed");
+ goto error_loop;
+ }
+
+ read(s3c2410_serial3_fd, &data, sizeof(data));
+
+ if(i > 50)
+ {
+ ipc_client_log(client, "crespo_ipc_bootstrap: fairly too much attempts to get ACK");
+ goto error_loop;
+ }
+ }
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: close s3c2410_serial3");
+ close(s3c2410_serial3_fd);
+
+ ipc_client_log(client, "crespo_ipc_bootstrap: writing the rest of radio.img to modem_ctl.");
+ /* Seek to the begining of modem_ctl_fd (should already be so). */
+ lseek(modem_ctl_fd, 0, SEEK_SET);
+
+ /* Pointer to the remaining part of radio.img. */
+ data_p=radio_img_p + PSI_DATA_LEN;
+
+ FD_ZERO(&fds);
+ FD_SET(modem_ctl_fd, &fds);
+
+ block_size = 0x100000;
+
+ for(i=0 ; i < (RADIO_IMG_SIZE - PSI_DATA_LEN) / block_size ; i++)
+ {
+ if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0)
+ {
+ ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed");
+ goto error_loop;
+ }
+
+ write(modem_ctl_fd, data_p, block_size);
+ data_p += block_size;
+ }
+
+ free(radio_img_p);
+
+ /* nv_data part. */
+
+ /* Check if all the nv_data files are ok. */
+ nv_data_check();
+
+ /* Check if the MD5 is ok. */
+ nv_data_md5_check();
+
+ /* Write nv_data.bin to modem_ctl. */
+ ipc_client_log(client, "crespo_ipc_bootstrap: write nv_data to modem_ctl");
+
+ nv_data_p = file_read("/efs/nv_data.bin", NV_DATA_SIZE, 1024);
+ if (nv_data_p == NULL)
+ goto error;
+ data_p = nv_data_p;
+
+ lseek(modem_ctl_fd, RADIO_IMG_SIZE, SEEK_SET);
+
+ for(i=0 ; i < 2 ; i++)
+ {
+ write(modem_ctl_fd, data_p, NV_DATA_SIZE / 2);
+ data_p += NV_DATA_SIZE / 2;
+ }
+
+ free(nv_data_p);
+
+ close(modem_ctl_fd);
+
+ rc = 0;
+ goto exit;
+
+error_loop:
+ ipc_client_log(client, "%s: something went wrong", __func__);
+ boot_tries_count++;
+ sleep(2);
+
+ goto boot_loop_start;
+
+error:
+ ipc_client_log(client, "%s: something went wrong", __func__);
+ rc = 1;
+exit:
+ ipc_client_log(client, "crespo_ipc_bootstrap: exit");
+ return rc;
+}
+
+int crespo_ipc_client_send(struct ipc_client *client, struct ipc_request *request)
+{
+ struct modem_io modem_data;
+ struct ipc_header reqhdr;
+ int rc = 0;
+
+ memset(&modem_data, 0, sizeof(struct modem_io));
+ modem_data.data = malloc(MAX_MODEM_DATA_SIZE);
+ modem_data.size = request->length + sizeof(struct ipc_header);
+
+ reqhdr.mseq = request->mseq;
+ reqhdr.aseq = request->aseq;
+ reqhdr.group = request->group;
+ reqhdr.index = request->index;
+ reqhdr.type = request->type;
+ reqhdr.length = (uint16_t) (request->length + sizeof(struct ipc_header));
+
+ modem_data.data = malloc(reqhdr.length);
+
+ memcpy(modem_data.data, &reqhdr, sizeof(struct ipc_header));
+ memcpy((unsigned char *)modem_data.data + sizeof(struct ipc_header), request->data, request->length);
+
+ assert(client->handlers->write != NULL);
+
+ rc = client->handlers->write((uint8_t*) &modem_data, sizeof(struct modem_io), client->handlers->io_data);
+ return rc;
+}
+
+int wake_lock(char *lock_name, int size)
+{
+ int rc = 0;
+
+ wake_lock_fd = open("/sys/power/wake_lock", O_RDWR);
+ rc = write(wake_lock_fd, lock_name, size);
+ close(wake_lock_fd);
+
+ return rc;
+}
+
+int wake_unlock(char *lock_name, int size)
+{
+ int rc = 0;
+
+ wake_lock_fd = open("/sys/power/wake_unlock", O_RDWR);
+ rc = write(wake_unlock_fd, lock_name, size);
+ close(wake_unlock_fd);
+
+ return rc;
+}
+
+int crespo_ipc_client_recv(struct ipc_client *client, struct ipc_response *response)
+{
+ struct modem_io modem_data;
+ struct ipc_header *resphdr;
+ int bread = 0;
+
+ memset(&modem_data, 0, sizeof(struct modem_io));
+ modem_data.data = malloc(MAX_MODEM_DATA_SIZE);
+ modem_data.size = MAX_MODEM_DATA_SIZE;
+
+ memset(response, 0, sizeof(struct ipc_response));
+
+ wake_lock("secril_fmt-interface", sizeof("secril_fmt-interface") - 1); // FIXME sizeof("...") is ugly!
+
+ assert(client->handlers->read != NULL);
+ bread = client->handlers->read((uint8_t*) &modem_data, sizeof(struct modem_io) + MAX_MODEM_DATA_SIZE, client->handlers->io_data);
+ if (bread < 0)
+ {
+ ipc_client_log(client, "ERROR: crespo_ipc_client_recv: can't receive enough bytes from modem to process incoming response!");
+ return 1;
+ }
+
+ ipc_client_log(client, "INFO: crespo_ipc_client_recv: Modem RECV FMT (id=%d cmd=%d size=%d)!", modem_data.id, modem_data.cmd, modem_data.size);
+
+ if(modem_data.size <= 0 || modem_data.size >= 0x1000 || modem_data.data == NULL)
+ {
+ ipc_client_log(client, "ERROR: crespo_ipc_client_recv: we retrieve less bytes from the modem than we exepected!");
+ return 1;
+ }
+
+ /* You MUST send back modem_data */
+
+ resphdr = (struct ipc_header *) modem_data.data;
+
+ response->mseq = resphdr->mseq;
+ response->aseq = resphdr->aseq;
+ response->command = IPC_COMMAND(resphdr);
+ response->type = resphdr->type;
+ response->data_length = modem_data.size - sizeof(struct ipc_header);
+ response->data = NULL;
+
+ ipc_client_log(client, "INFO: crespo_ipc_client_recv: response: group = %d, index = %d, command = %04x",
+ resphdr->group, resphdr->index, response->command);
+
+ if(response->data_length > 0)
+ {
+ response->data = malloc(response->data_length);
+ memcpy(response->data, (uint8_t *) modem_data.data + sizeof(struct ipc_header), response->data_length);
+ }
+
+ free(modem_data.data);
+
+ wake_unlock("secril_fmt-interface", sizeof("secril_fmt-interface") - 1); // FIXME sizeof("...") is ugly!
+
+ return 0;
+}
+
+int crespo_ipc_open(void *data, unsigned int size, void *io_data)
+{
+ int type=*((int *) data);
+ int fd=-1;
+
+ switch(type)
+ {
+ case IPC_CLIENT_TYPE_CRESPO_FMT:
+ fd = open("/dev/modem_fmt", O_RDWR | O_NDELAY);
+ printf("crespo_ipc_open: opening /dev/modem_fmt\n");
+ break;
+ case IPC_CLIENT_TYPE_CRESPO_RFS:
+ fd = open("/dev/modem_rfs", O_RDWR | O_NDELAY);
+ printf("crespo_ipc_open: opening /dev/modem_rfs\n");
+ break;
+ default:
+ break;
+ }
+
+ if(fd < 0)
+ return -1;
+
+ if(io_data == NULL)
+ return -1;
+
+ memcpy(io_data, &fd, sizeof(int));
+
+ return 0;
+}
+
+int crespo_ipc_close(void *data, unsigned int size, void *io_data)
+{
+ int fd = -1;
+
+ if(io_data == NULL)
+ return -1;
+
+ fd = *((int *) io_data);
+
+ if(fd < 0)
+ return -1;
+
+ close(fd);
+
+ return 0;
+}
+
+int crespo_ipc_read(void *data, unsigned int size, void *io_data)
+{
+ int fd = -1;
+ int rc;
+
+ if(io_data == NULL)
+ return -1;
+
+ if(data == NULL)
+ return -1;
+
+ fd = *((int *) io_data);
+
+ if(fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_RECV, data);
+
+ if(rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_ipc_write(void *data, unsigned int size, void *io_data)
+{
+ int fd = -1;
+ int rc;
+
+ if(io_data == NULL)
+ return -1;
+
+ fd = *((int *) io_data);
+
+ if(fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_SEND, data);
+
+ if(rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_ipc_power_on(void *data)
+{
+ int fd=open("/dev/modem_ctl", O_RDWR);
+ int rc;
+
+/*
+ fd = open("/sys/devices/platform/modemctl/power_mode", O_RDWR);
+ rc = write(fd, "1", 1);
+*/
+
+ if(fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_START);
+ close(fd);
+
+ if(rc < 0)
+ return -1;
+
+ return 0;
+}
+
+int crespo_ipc_power_off(void *data)
+{
+ int fd=open("/dev/modem_ctl", O_RDWR);
+ int rc;
+
+/*
+ fd = open("/sys/devices/platform/modemctl/power_mode", O_RDWR);
+ rc = write(fd, "0", 1);
+*/
+
+ if(fd < 0)
+ return -1;
+
+ rc = ioctl(fd, IOCTL_MODEM_OFF);
+ close(fd);
+
+ if(rc < 0)
+ return -1;
+
+ return 0;
+}
+
+void *crespo_ipc_io_data_reg(void)
+{
+ void *data = NULL;
+
+ data = malloc(sizeof(int));
+
+ return data;
+}
+
+int crespo_ipc_io_data_unreg(void *data)
+{
+ if(data == NULL)
+ return -1;
+
+ free(data);
+
+ return 0;
+}
+
+struct ipc_handlers ipc_default_handlers = {
+ .read = crespo_ipc_read,
+ .write = crespo_ipc_write,
+ .open = crespo_ipc_open,
+ .close = crespo_ipc_close,
+ .io_data_reg = crespo_ipc_io_data_reg,
+ .io_data_unreg = crespo_ipc_io_data_unreg,
+ .io_data = NULL,
+ .power_on = crespo_ipc_power_on,
+ .power_off = crespo_ipc_power_off,
+};
+
+struct ipc_ops ipc_ops = {
+ .send = crespo_ipc_client_send,
+ .recv = crespo_ipc_client_recv,
+ .bootstrap = crespo_modem_bootstrap,
+};
diff --git a/samsung-ipc/device/crespo/crespo_ipc.h b/samsung-ipc/device/crespo/crespo_ipc.h
new file mode 100644
index 0000000..a6540b5
--- /dev/null
+++ b/samsung-ipc/device/crespo/crespo_ipc.h
@@ -0,0 +1,50 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 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 3 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 __CRESPO_IPC_H__
+#define __CRESPO_IPC_H__
+
+#define BOOTCORE_VERSION 0xf0
+#define PSI_MAGIC 0x30
+#define PSI_DATA_LEN 0x5000
+#define RADIO_IMG_SIZE 0xd80000
+
+#define MAX_MODEM_DATA_SIZE 0x1000
+
+struct samsung_rfs_msg
+{
+ uint32_t offset;
+ uint32_t size;
+};
+
+struct samsung_rfs_cfrm
+{
+ uint8_t confirmation;
+ struct samsung_rfs_msg msg;
+};
+
+void *mtd_read(char *mtd_name, int size, int block_size);
+void *file_read(char *file_name, int size, int block_size);
+int wake_lock(char *lock_name, int size);
+int wake_unlock(char *lock_name, int size);
+
+extern struct ipc_handlers crespo_ipc_default_handlers;
+
+#endif
diff --git a/samsung-ipc/device/crespo/crespo_modem_ctl.h b/samsung-ipc/device/crespo/crespo_modem_ctl.h
new file mode 100644
index 0000000..7c23165
--- /dev/null
+++ b/samsung-ipc/device/crespo/crespo_modem_ctl.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2010 Samsung Electronics.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program 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.
+ *
+ */
+
+#ifndef __MODEM_CONTROL_H__
+#define __MODEM_CONTROL_H__
+
+#define IOCTL_MODEM_RAMDUMP _IO('o', 0x19)
+#define IOCTL_MODEM_RESET _IO('o', 0x20)
+#define IOCTL_MODEM_START _IO('o', 0x21)
+#define IOCTL_MODEM_OFF _IO('o', 0x22)
+
+#define IOCTL_MODEM_SEND _IO('o', 0x23)
+#define IOCTL_MODEM_RECV _IO('o', 0x24)
+
+struct modem_io {
+ uint32_t size;
+ uint32_t id;
+ uint32_t cmd;
+ void *data;
+};
+
+/* platform data */
+struct modemctl_data {
+ const char *name;
+ unsigned gpio_phone_active;
+ unsigned gpio_pda_active;
+ unsigned gpio_cp_reset;
+ unsigned gpio_phone_on;
+ bool is_cdma_modem; /* 1:CDMA Modem */
+};
+
+#endif
diff --git a/samsung-ipc/device/crespo/crespo_nv_data.c b/samsung-ipc/device/crespo/crespo_nv_data.c
new file mode 100644
index 0000000..58b034e
--- /dev/null
+++ b/samsung-ipc/device/crespo/crespo_nv_data.c
@@ -0,0 +1,353 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 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 3 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <openssl/md5.h>
+
+#include "crespo_nv_data.h"
+#include "crespo_ipc.h"
+
+void md5hash2string(char *out, uint8_t *in)
+{
+ int i;
+
+ for(i=0 ; i < MD5_DIGEST_LENGTH ; i++)
+ {
+ /* After the first iteration, we override \0. */
+ if(*in < 0x10)
+ sprintf(out, "0%x", *in);
+ else
+ sprintf(out, "%x", *in);
+ in++;
+ out+=2;
+ }
+}
+
+void nv_data_generate(void)
+{
+ printf("This feature isn't present yet\n");
+
+// nv_data_backup_create();
+}
+
+void nv_data_md5_compute(void *data_p, int size, void *hash)
+{
+ MD5_CTX ctx;
+
+// MD5((unsigned char *)nv_data_p, nv_data_stat.st_size, nv_data_md5_hash);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, data_p, size);
+ MD5_Update(&ctx, NV_DATA_MD5_SECRET, sizeof(NV_DATA_MD5_SECRET) - 1);
+ MD5_Final(hash, &ctx);
+}
+
+void nv_data_backup_create(void)
+{
+ uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
+ char *nv_data_md5_hash_string;
+
+ struct stat nv_stat;
+ void *nv_data_p;
+ uint8_t data;
+ uint8_t *data_p;
+
+ int fd;
+ int i;
+
+ printf("nv_data_backup_create: enter\n");
+
+ if(stat("/efs/nv_data.bin", &nv_stat) < 0)
+ {
+ printf("nv_data_check: nv_data.bin missing\n");
+ nv_data_generate();
+ }
+
+ /* Read the content of nv_data.bin. */
+ nv_data_p=file_read("/efs/nv_data.bin", NV_DATA_SIZE, NV_DATA_SIZE / 10);
+
+ fd=open("/efs/.nv_data.bak", O_RDWR | O_CREAT, 0644);
+
+ data_p=nv_data_p;
+
+ /* Write the content of nv_data.bin in the backup file. */
+ for(i=0 ; i < NV_DATA_SIZE / 10 ; i++)
+ {
+ write(fd, data_p, NV_DATA_SIZE / 10);
+ data_p+=NV_DATA_SIZE / 10;
+ }
+
+ close(fd);
+ free(nv_data_p);
+
+ /* Alloc the memory for the md5 hash string. */
+ nv_data_md5_hash_string=malloc(MD5_STRING_SIZE);
+ memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
+
+ /* Read the newly-written .nv_data.bak. */
+ nv_data_p=file_read("/efs/.nv_data.bak", NV_DATA_SIZE, NV_DATA_SIZE / 10);
+
+ /* Compute the MD5 hash for .nv_data.bak.. */
+ nv_data_md5_compute(nv_data_p, NV_DATA_SIZE, nv_data_md5_hash);
+ md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
+
+ printf("nv_data_backup_create: new MD5 hash is %s\n", nv_data_md5_hash_string);
+
+ free(nv_data_p);
+
+ /* Write the MD5 hash in nv_data.bin.md5. */
+ fd=open("/efs/.nv_data.bak.md5", O_RDWR | O_CREAT, 0644);
+
+ write(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
+
+ close(fd);
+ free(nv_data_md5_hash_string);
+
+ /* Write ASCII 1 on the state file. */
+ fd=open("/efs/.nv_state", O_RDWR | O_CREAT, 0644);
+
+ data='1';
+ write(fd, &data, sizeof(data));
+
+ close(fd);
+
+ printf("nv_data_backup_create: exit\n");
+}
+
+void nv_data_backup_restore(void)
+{
+ uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
+ char *nv_data_md5_hash_string;
+ char *nv_data_md5_hash_read;
+
+ struct stat nv_stat;
+ void *nv_data_p;
+ uint8_t data;
+ uint8_t *data_p;
+
+ int fd;
+ int i;
+
+ printf("nv_data_backup_restore: enter\n");
+
+ if(stat("/efs/.nv_data.bak", &nv_stat) < 0)
+ {
+ printf("nv_data_backup_restore: .nv_data.bak missing\n");
+ nv_data_generate();
+ nv_data_backup_create();
+ return;
+ }
+
+ if(nv_stat.st_size != NV_DATA_SIZE)
+ {
+ printf("nv_data_backup_restore: wrong .nv_data.bak size\n");
+ nv_data_generate();
+ nv_data_backup_create();
+ return;
+ }
+
+ /* Read the content of the backup file. */
+ nv_data_p=file_read("/efs/.nv_data.bak", NV_DATA_SIZE, NV_DATA_SIZE / 10);
+
+ fd=open("/efs/nv_data.bin", O_RDWR | O_CREAT, 0644);
+
+ data_p=nv_data_p;
+
+ /* Write the content of the backup file in nv_data.bin. */
+ for(i=0 ; i < NV_DATA_SIZE / 10 ; i++)
+ {
+ write(fd, data_p, NV_DATA_SIZE / 10);
+ data_p+=NV_DATA_SIZE / 10;
+ }
+
+ close(fd);
+ free(nv_data_p);
+
+ /* Alloc the memory for the md5 hashes strings. */
+ nv_data_md5_hash_string=malloc(MD5_STRING_SIZE);
+ nv_data_md5_hash_read=malloc(MD5_STRING_SIZE);
+
+ memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
+ memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
+
+ /* Read the newly-written nv_data.bin. */
+ nv_data_p=file_read("/efs/nv_data.bin", NV_DATA_SIZE, NV_DATA_SIZE / 10);
+
+ /* Compute the MD5 hash for nv_data.bin. */
+ nv_data_md5_compute(nv_data_p, NV_DATA_SIZE, nv_data_md5_hash);
+ md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
+
+ free(nv_data_p);
+
+ /* Open the backup file MD5 hash. */
+ fd=open("/efs/.nv_data.bak.md5", O_RDONLY);
+
+ /* Read the md5 stored in the file. */
+ read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
+
+ /* Add 0x0 to end the string: not sure this is part of the file. */
+ nv_data_md5_hash_read[MD5_STRING_SIZE - 1]='\0';
+
+ printf("nv_data_backup_restore: computed MD5: %s read MD5: %s\n",
+ nv_data_md5_hash_string, nv_data_md5_hash_read);
+
+ /* Make sure both hashes are the same. */
+ if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
+ {
+ printf("nv_data_md5_check: MD5 hash mismatch\n");
+ nv_data_generate();
+ nv_data_backup_create();
+ return;
+ }
+
+ close(fd);
+
+ /* Write the MD5 hash in nv_data.bin.md5. */
+ fd=open("/efs/nv_data.bin.md5", O_RDWR | O_CREAT, 0644);
+
+ write(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
+
+ close(fd);
+
+ free(nv_data_md5_hash_string);
+ free(nv_data_md5_hash_read);
+
+ fd=open("/efs/.nv_state", O_RDWR | O_CREAT, 0644);
+
+ data='1';
+ write(fd, &data, sizeof(data));
+
+ close(fd);
+
+ printf("nv_data_backup_create: exit\n");
+}
+
+void nv_data_check(void)
+{
+ struct stat nv_stat;
+ int nv_state_fd=-1;
+ int nv_state=0;
+
+ printf("nv_data_check: enter\n");
+
+ if(stat("/efs/nv_data.bin", &nv_stat) < 0)
+ {
+ printf("nv_data_check: nv_data.bin missing\n");
+ nv_data_backup_restore();
+ stat("/efs/nv_data.bin", &nv_stat);
+ }
+
+ if(nv_stat.st_size != NV_DATA_SIZE)
+ {
+ printf("nv_data_check: wrong nv_data.bin size\n");
+ nv_data_backup_restore();
+ }
+
+ if(stat("/efs/.nv_data.bak", &nv_stat) < 0)
+ {
+ printf("nv_data_check: .nv_data.bak missing\n");
+ nv_data_backup_create();
+ }
+
+ if(stat("/efs/nv_data.bin.md5", &nv_stat) < 0)
+ {
+ printf("nv_data_check: nv_data.bin.md5 missing\n");
+ nv_data_backup_create();
+ }
+
+ nv_state_fd=open("/efs/.nv_state", O_RDONLY);
+
+ if(nv_state_fd < 0 || fstat(nv_state_fd, &nv_stat) < 0)
+ {
+ printf("nv_data_check: .nv_state missing\n");
+ nv_data_backup_restore();
+ }
+
+ read(nv_state_fd, &nv_state, sizeof(nv_state));
+
+ close(nv_state_fd);
+
+ if(nv_state != '1')
+ {
+ printf("nv_data_check: bad nv_state\n");
+ nv_data_backup_restore();
+ }
+
+ printf("nv_data_check: everything should be alright\n");
+ printf("nv_data_check: exit\n");
+}
+
+void nv_data_md5_check(void)
+{
+ struct stat nv_stat;
+ uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
+ char *nv_data_md5_hash_string;
+ char *nv_data_md5_hash_read;
+ void *nv_data_p;
+
+ int fd;
+ uint8_t *data_p;
+
+ printf("nv_data_md5_check: enter\n");
+
+ nv_data_md5_hash_string=malloc(MD5_STRING_SIZE);
+ nv_data_md5_hash_read=malloc(MD5_STRING_SIZE);
+
+ memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
+ memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
+
+ nv_data_p=file_read("/efs/nv_data.bin", NV_DATA_SIZE, 1024);
+ data_p=nv_data_p;
+
+ nv_data_md5_compute(data_p, NV_DATA_SIZE, nv_data_md5_hash);
+
+ md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
+
+ free(nv_data_p);
+
+ fd=open("/efs/nv_data.bin.md5", O_RDONLY);
+
+ /* Read the md5 stored in the file. */
+ read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
+
+ /* Add 0x0 to end the string: not sure this is part of the file. */
+ nv_data_md5_hash_read[MD5_STRING_SIZE - 1]='\0';
+
+ printf("nv_data_md5_check: computed MD5: %s read MD5: %s\n",
+ nv_data_md5_hash_string, nv_data_md5_hash_read);
+
+ if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
+ {
+ printf("nv_data_md5_check: MD5 hash mismatch\n");
+ nv_data_backup_restore();
+ }
+
+ free(nv_data_md5_hash_string);
+ free(nv_data_md5_hash_read);
+
+ printf("nv_data_md5_check: exit\n");
+}
diff --git a/samsung-ipc/device/crespo/crespo_nv_data.h b/samsung-ipc/device/crespo/crespo_nv_data.h
new file mode 100644
index 0000000..bc17416
--- /dev/null
+++ b/samsung-ipc/device/crespo/crespo_nv_data.h
@@ -0,0 +1,37 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 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 3 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 __CRESPO_NV_DATA_H__
+#define __CRESPO_NV_DATA__
+
+#define NV_DATA_MD5_SECRET "Samsung_Android_RIL"
+#define NV_DATA_SIZE 0x200000
+
+#define MD5_STRING_SIZE MD5_DIGEST_LENGTH * 2 + 1
+
+void md5hash2string(char *out, uint8_t *in);
+void nv_data_generate(void);
+void nv_data_md5_compute(void *data_p, int size, void *hash);
+void nv_data_backup_create(void);
+void nv_data_backup_restore(void);
+void nv_data_check(void);
+void nv_data_md5_check(void);
+
+#endif
diff --git a/samsung-ipc/device/h1/h1_ipc.c b/samsung-ipc/device/h1/h1_ipc.c
new file mode 100644
index 0000000..49408ba
--- /dev/null
+++ b/samsung-ipc/device/h1/h1_ipc.c
@@ -0,0 +1,169 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.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 3 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 <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "ipc_private.h"
+#include "h1_ipc.h"
+
+/* FIXME: move to io_data */
+static int fd = 0;
+
+int h1_ipc_open()
+{
+ struct termios termios;
+
+ fd = open(DPRAM_TTY, O_RDWR);
+
+ if(fd < 0) {
+ return 1;
+ }
+
+ tcgetattr(fd, &termios);
+ cfmakeraw(&termios);
+ tcsetattr(fd, TCSANOW, &termios);
+
+ return 0;
+}
+
+int h1_ipc_close()
+{
+ if(fd) {
+ return close(fd);
+ }
+
+ return 0;
+}
+
+int h1_ipc_power_on()
+{
+ ioctl(fd, IOCTL_PHONE_ON);
+
+ return 0;
+}
+
+int h1_ipc_power_off()
+{
+ ioctl(fd, IOCTL_PHONE_OFF);
+
+ return 0;
+}
+
+int h1_ipc_send(struct ipc_client *client, struct ipc_request *request)
+{
+ struct hdlc_header *hdlc;
+ unsigned char *frame;
+ int frame_length;
+
+ /* Frame length: HDLC/IPC header + payload length + HDLC flags (2) */
+ frame_length = (sizeof(*hdlc) + request->length + 2);
+
+ frame = (unsigned char*)malloc(frame_length);
+ frame[0] = FRAME_START;
+ frame[frame_length-1] = FRAME_END;
+
+ /* Setup HDLC header */
+ hdlc = (struct hdlc_header*)(frame + 1);
+
+ hdlc->length = (sizeof(*hdlc) + request->length);
+ hdlc->unknown = 0;
+
+ /* IPC data */
+ hdlc->ipc.length = (sizeof(hdlc->ipc) + request->length);
+ hdlc->ipc.mseq = request->mseq;
+ hdlc->ipc.aseq = request->aseq;
+ hdlc->ipc.group = request->group;
+ hdlc->ipc.index = request->index;
+ hdlc->ipc.type = request->type;
+
+ hex_dump(frame, frame_length);
+
+ client->handlers->write(frame, frame_length, client->handlers->io_data);
+
+ free(frame);
+
+ return 0;
+}
+
+int h1_ipc_recv(struct ipc_client *client, struct ipc_response *response)
+{
+ unsigned char buf[4];
+ unsigned char *data;
+ unsigned short *frame_length;
+ struct ipc_header *ipc;
+ int num_read;
+ int left;
+
+ num_read = client->handlers->read((void*)buf, sizeof(buf), client->handlers->io_data);
+
+ if(num_read == sizeof(buf) && *buf == FRAME_START) {
+ frame_length = (unsigned short*)&buf[1];
+ left = (*frame_length - 3 + 1);
+
+ data = (unsigned char*)malloc(left);
+ num_read = client->handlers->read((void*)data, left, client->handlers->io_data);
+
+ if(num_read == left && data[left-1] == FRAME_END) {
+ ipc = (struct ipc_header*)data;
+ response->mseq = ipc->mseq;
+ response->aseq = ipc->aseq;
+ response->command = IPC_COMMAND(ipc);
+ response->type = ipc->type;
+ response->data_length = (ipc->length - sizeof(*ipc));
+
+ response->data = (unsigned char*)malloc(response->data_length);
+ memcpy(response->data, (data + sizeof(*ipc)), response->data_length);
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+int h1_ipc_read(void *data, unsigned int size, void *io_data)
+{
+ return read(fd, data, size);
+}
+
+int h1_ipc_write(void *data, unsigned int size, void *io_data)
+{
+ return write(fd, data, size);
+}
+
+struct ipc_handlers ipc_default_handlers = {
+ .open = h1_ipc_open,
+ .close = h1_ipc_close,
+ .power_on = h1_ipc_power_on,
+ .power_off = h1_ipc_power_off,
+ .read = h1_ipc_read,
+ .write = h1_ipc_write,
+ .io_data_reg = NULL,
+ .io_data_unreg = NULL,
+ .io_data = NULL,
+};
+
+struct ipc_ops ipc_ops = {
+ .send = h1_ipc_send,
+ .recv = h1_ipc_recv,
+ .bootstrap = NULL,
+};
diff --git a/samsung-ipc/device/h1/h1_ipc.h b/samsung-ipc/device/h1/h1_ipc.h
new file mode 100644
index 0000000..1bbc951
--- /dev/null
+++ b/samsung-ipc/device/h1/h1_ipc.h
@@ -0,0 +1,44 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.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 3 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 <radio.h>
+
+#define DPRAM_TTY "/dev/dpram0"
+
+#define IOCTL_PHONE_ON 0x68d0
+#define IOCTL_PHONE_OFF 0x68d1
+#define IOCTL_PHONE_GETSTATUS 0x68d2
+#define IOCTL_PHONE_RESET 0x68d3
+#define IOCTL_PHONE_RAMDUMP 0x68d4
+#define IOCTL_PHONE_BOOTTYPE 0x68d5
+#define IOCTL_MEM_RW 0x68d6
+#define IOCTL_WAKEUP 0x68d7
+#define IOCTL_SILENT_RESET 0x68d8
+
+#define FRAME_START 0x7f
+#define FRAME_END 0x7e
+
+struct hdlc_header {
+ unsigned short length;
+ unsigned char unknown;
+
+ struct ipc_header ipc;
+} __attribute__((__packed__));
+