aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulK <contact@paulk.fr>2011-08-18 22:39:58 +0200
committerJoerie de Gram <j.de.gram@gmail.com>2011-08-19 00:07:01 +0200
commitf74d8e2c179065bd8712b113b65957c617ad6c54 (patch)
treeff52a249f3f91acf3fc999c7cc5299e922b19a11
parent31ecac1c244e69748617e3b88a84dbbffd3d5601 (diff)
downloadexternal_libsamsung-ipc-f74d8e2c179065bd8712b113b65957c617ad6c54.zip
external_libsamsung-ipc-f74d8e2c179065bd8712b113b65957c617ad6c54.tar.gz
external_libsamsung-ipc-f74d8e2c179065bd8712b113b65957c617ad6c54.tar.bz2
devices: add support for Nexus S
As for now, it features: * booting the modem * the ability to receive and send messages from/to the modem The messages received from the modem are in a known format and can be understood easilly, and it's also possible to send messages to the modem in that very same known format.
-rw-r--r--Android.mk12
-rw-r--r--devices/crespo/ipc.c512
-rw-r--r--devices/crespo/ipc.h45
-rw-r--r--devices/crespo/modem_ctl.h44
-rw-r--r--devices/crespo/nv_data.c353
-rw-r--r--devices/crespo/nv_data.h37
6 files changed, 1003 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
index f856eab..dacd080 100644
--- a/Android.mk
+++ b/Android.mk
@@ -13,6 +13,12 @@ LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := $(libsamsung-ipc_files)
+ifeq ($(TARGET_DEVICE),crespo)
+ libsamsung-ipc_files += devices/$(TARGET_DEVICE)/nv_data.c
+ LOCAL_CFLAGS += -Iexternal/openssl/include
+ LOCAL_LDFLAGS += -lcrypto
+endif
+
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -26,5 +32,11 @@ LOCAL_CFLAGS := -DLOG_STDOUT
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := $(libsamsung-ipc_files) test.c
+ifeq ($(TARGET_DEVICE),crespo)
+ libsamsung-ipc_files += devices/$(TARGET_DEVICE)/nv_data.c
+ LOCAL_CFLAGS += -Iexternal/openssl/include
+ LOCAL_LDFLAGS += -lcrypto
+endif
+
include $(BUILD_EXECUTABLE)
diff --git a/devices/crespo/ipc.c b/devices/crespo/ipc.c
new file mode 100644
index 0000000..71db822
--- /dev/null
+++ b/devices/crespo/ipc.c
@@ -0,0 +1,512 @@
+/**
+ * This file is part of libsamsung-ipc.
+ *
+ * Copyright (C) 2011 Paul Kocialkowski <contact@paulk.fr>
+ * Copyright (C) 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 <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 <radio.h>
+
+#include "modem_ctl.h"
+#include "nv_data.h"
+#include "ipc.h"
+
+int s3c2410_serial3_fd= -1;
+int modem_ctl_fd= -1;
+int modem_fmt_fd= -1;
+int modem_rfs_fd= -1;
+int wake_lock_fd= -1;
+int wake_unlock_fd= -1;
+
+void *mtd_read(char *mtd_name, int size, int block_size)
+{
+ void *mtd_p=NULL;
+ uint8_t *data_p=NULL;
+
+ loff_t offs;
+ int fd;
+ int i;
+
+ if(mtd_name == NULL || size <= 0 || block_size <= 0)
+ goto error;
+
+ printf("mtd_read: reading 0x%x bytes from %s with 0x%x bytes block size\n", size, mtd_name, block_size);
+
+ mtd_p=malloc(size);
+ if(mtd_p == NULL)
+ goto error;
+
+ memset(mtd_p, 0, size);
+
+ data_p=(uint8_t *) mtd_p;
+
+ fd=open(mtd_name, O_RDONLY);
+ if(fd < 0)
+ goto error;
+
+ for(i=0 ; i < size / block_size ; i++)
+ {
+ offs=i * block_size;
+ if(ioctl(fd, MEMGETBADBLOCK, &offs) == 1)
+ {
+ printf("mtd_read: warning: bad block at offset %lld\n", offs);
+ data_p+=block_size;
+ continue;
+ }
+
+ read(fd, data_p, block_size);
+ data_p+=block_size;
+ }
+
+ close(fd);
+
+ return mtd_p;
+
+error:
+ printf("%s: something went wrong\n", __func__);
+ return NULL;
+}
+
+void *file_read(char *file_name, int size, int block_size)
+{
+ void *file_p=NULL;
+ uint8_t *data_p=NULL;
+
+ int fd;
+ int i;
+
+ if(file_name == NULL || size <= 0 || block_size <= 0)
+ goto error;
+
+ printf("file_read: reading 0x%x bytes from %s with 0x%x bytes block size\n", size, file_name, block_size);
+
+ file_p=malloc(size);
+ if(file_p == NULL)
+ goto error;
+
+ memset(file_p, 0, size);
+
+ data_p=(uint8_t *) file_p;
+
+ fd=open(file_name, O_RDONLY);
+ if(fd < 0)
+ goto error;
+
+ for(i=0 ; i < size / block_size ; i++)
+ {
+ read(fd, data_p, block_size);
+ data_p+=block_size;
+ }
+
+ close(fd);
+
+ return file_p;
+
+error:
+ printf("%s: something went wrong\n", __func__);
+ return NULL;
+}
+
+int ipc_open(void)
+{
+ /* 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;
+
+ printf("ipc_open: enter\n");
+
+boot_loop_start:
+ if(boot_tries_count > 5)
+ {
+ printf("ipc_open: boot has failed too many times.\n");
+ goto error;
+ }
+
+ /* Read the radio.img image. */
+ printf("ipc_open: reading radio image\n");
+ radio_img_p=mtd_read("/dev/mtd/mtd5ro", RADIO_IMG_SIZE, 0x1000);
+ printf("ipc_open: radio image read\n");
+
+ printf("ipc_open: open modem_ctl\n");
+ 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);
+
+ printf("ipc_open: open s3c2410_serial3\n");
+ s3c2410_serial3_fd=open("/dev/s3c2410_serial3", O_RDWR | O_NDELAY);
+ if(s3c2410_serial3_fd < 0)
+ goto error_loop;
+
+ /* Setup the s3c2410 serial. */
+ printf("ipc_open: setup s3c2410_serial3\n");
+ 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. */
+ printf("ipc_open: sending AT in ASCII\n");
+ for(i=0 ; i < 20 ; i++)
+ {
+ write(s3c2410_serial3_fd, "AT", 2);
+ usleep(50000);
+ }
+ printf("ipc_open: sending AT in ASCII done\n");
+
+ usleep(50000); //FIXME
+
+ /* Get and check bootcore version. */
+ read(s3c2410_serial3_fd, &bootcore_version, sizeof(bootcore_version));
+ printf("ipc_open: got bootcore version: 0x%x\n", bootcore_version);
+
+ if(bootcore_version != BOOTCORE_VERSION)
+ goto error_loop;
+
+ /* Get info_size. */
+ read(s3c2410_serial3_fd, &info_size, sizeof(info_size));
+ printf("ipc_open: got info_size: 0x%x\n", info_size);
+
+ /* Send PSI magic. */
+ data=PSI_MAGIC;
+ write(s3c2410_serial3_fd, &data, sizeof(data));
+ printf("ipc_open: sent PSI_MAGIC (0x%x)\n", 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++;
+ }
+ printf("ipc_open: sent PSI_DATA_LEN (0x%x)\n", 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;
+
+ printf("ipc_open: sending the first part of radio.img\n");
+
+ for(i=0 ; i < PSI_DATA_LEN ; i++)
+ {
+ if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0)
+ {
+ printf("ipc_open: select timeout passed\n");
+ goto error_loop;
+ }
+
+ write(s3c2410_serial3_fd, data_p, 1);
+ crc_byte=crc_byte ^ *data_p;
+
+ data_p++;
+ }
+
+ printf("ipc_open: first part of radio.img sent; crc_byte is 0x%x\n", crc_byte);
+
+ if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0)
+ {
+ printf("ipc_open: select timeout passed\n");
+ goto error_loop;
+ }
+
+ write(s3c2410_serial3_fd, &crc_byte, sizeof(crc_byte));
+
+ printf("ipc_open: crc_byte sent\n");
+
+ data=0;
+ for(i=0 ; data != 0x01 ; i++)
+ {
+ if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0)
+ {
+ printf("ipc_open: select timeout passed\n");
+ goto error_loop;
+ }
+
+ read(s3c2410_serial3_fd, &data, sizeof(data));
+
+ if(i > 50)
+ {
+ printf("ipc_open: fairly too much attempts to get ACK\n");
+ goto error_loop;
+ }
+ }
+
+ printf("ipc_open: close s3c2410_serial3\n");
+ close(s3c2410_serial3_fd);
+
+ printf("ipc_open: writing the rest of radio.img to modem_ctl.\n");
+ /* 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)
+ {
+ printf("ipc_open: select timeout passed\n");
+ 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. */
+ printf("ipc_open: write nv_data to modem_ctl\n");
+
+ nv_data_p=file_read("/efs/nv_data.bin", NV_DATA_SIZE, 1024);
+ 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);
+
+ modem_fmt_fd=open("/dev/modem_fmt", O_RDWR | O_NDELAY);
+ modem_rfs_fd=open("/dev/modem_rfs", O_RDWR | O_NDELAY);
+
+ rc=0;
+ goto exit;
+
+error_loop:
+ printf("%s: something went wrong\n", __func__);
+ boot_tries_count++;
+ sleep(2);
+
+ goto boot_loop_start;
+
+error:
+ printf("%s: something went wrong\n", __func__);
+ rc=1;
+exit:
+ printf("ipc_open: exit\n");
+ return rc;
+}
+
+int ipc_close(void)
+{
+ close(modem_fmt_fd);
+ close(modem_rfs_fd);
+ close(modem_ctl_fd);
+
+ return 0;
+}
+
+void ipc_power_on(void)
+{
+ ioctl(modem_ctl_fd, IOCTL_MODEM_START);
+}
+
+void ipc_power_off(void)
+{
+ ioctl(modem_ctl_fd, IOCTL_MODEM_OFF);
+}
+
+void ipc_send(struct ipc_request *request)
+{
+ struct modem_io modem_data;
+ struct ipc_header hdlc_data;
+ uint8_t *data_p;
+
+ memset(&modem_data, 0, sizeof(struct modem_io));
+ modem_data.data=malloc(0x1000);
+ modem_data.size=request->length + sizeof(struct ipc_header);
+
+ hdlc_data.mseq=request->mseq;
+ hdlc_data.aseq=request->aseq;
+ hdlc_data.group=request->group;
+ hdlc_data.index=request->index;
+ hdlc_data.type=request->type;
+ hdlc_data.length=(uint16_t) (request->length + sizeof(struct ipc_header));
+
+ modem_data.data=malloc(hdlc_data.length);
+ data_p=modem_data.data;
+
+ memcpy(data_p, &hdlc_data, sizeof(struct ipc_header));
+ data_p+=sizeof(struct ipc_header);
+ memcpy(data_p, request->data, request->length);
+
+ ioctl(modem_fmt_fd, IOCTL_MODEM_SEND, &modem_data);
+}
+
+void wake_lock(char *lock_name, int size)
+{
+ if(wake_lock_fd < 0)
+ wake_lock_fd=open("/sys/power/wake_lock", O_RDWR);
+
+ write(wake_lock_fd, lock_name, size);
+}
+
+void wake_unlock(char *lock_name, int size)
+{
+ if(wake_unlock_fd < 0)
+ wake_lock_fd=open("/sys/power/wake_unlock", O_RDWR);
+
+ write(wake_unlock_fd, lock_name, size);
+}
+
+int ipc_recv(struct ipc_response *response)
+{
+ struct modem_io modem_data;
+ struct ipc_header *hdlc_data;
+
+ fd_set fds;
+
+recv_loop_start:
+ memset(&modem_data, 0, sizeof(struct modem_io));
+ modem_data.data=malloc(0x1000);
+ modem_data.size=0x1000;
+
+ memset(response, 0, sizeof(struct ipc_response));
+
+ /* TODO: Should be with the wakelocks. */
+
+ wake_lock("secril_fmt-interface", sizeof("secril_fmt-interface") - 1);
+
+ FD_ZERO(&fds);
+ FD_SET(modem_fmt_fd, &fds);
+ FD_SET(modem_rfs_fd, &fds);
+
+ select(FD_SETSIZE, &fds, NULL, NULL, NULL);
+
+ if(FD_ISSET(modem_rfs_fd, &fds))
+ {
+ ioctl(modem_rfs_fd, IOCTL_MODEM_RECV, &modem_data);
+ printf("ipc_recv: Modem RECV RFS (id=%d cmd=%d size=%d)!\n", modem_data.id, modem_data.cmd, modem_data.size);
+ free(modem_data.data);
+ wake_unlock("secril_fmt-interface", sizeof("secril_fmt-interface") - 1);
+
+ goto recv_loop_start;
+ return 0;
+ }
+
+ if(FD_ISSET(modem_fmt_fd, &fds))
+ {
+ ioctl(modem_fmt_fd, IOCTL_MODEM_RECV, &modem_data);
+ printf("ipc_recv: Modem RECV FMT (id=%d cmd=%d size=%d)!\n", modem_data.id, modem_data.cmd, modem_data.size);
+
+ if(modem_data.size <= 0 || modem_data.size >= 0x1000 || modem_data.data == NULL)
+ {
+ printf("ipc_recv: Something is wrong with the received message\n");
+ return 1;
+ }
+
+ hdlc_data=(struct ipc_header *) modem_data.data;
+
+ response->mseq=hdlc_data->mseq;
+ response->aseq=hdlc_data->aseq;
+ response->command=IPC_COMMAND(hdlc_data);
+ response->type=hdlc_data->type;
+ response->data_length=modem_data.size - sizeof(struct ipc_header);
+
+ 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);
+ }
+ else
+ {
+ response->data=NULL;
+ }
+
+ free(modem_data.data);
+
+ wake_unlock("secril_fmt-interface", sizeof("secril_fmt-interface") - 1);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/devices/crespo/ipc.h b/devices/crespo/ipc.h
new file mode 100644
index 0000000..7001d2a
--- /dev/null
+++ b/devices/crespo/ipc.h
@@ -0,0 +1,45 @@
+/**
+ * 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
+
+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);
+void wake_lock(char *lock_name, int size);
+void wake_unlock(char *lock_name, int size);
+#endif
diff --git a/devices/crespo/modem_ctl.h b/devices/crespo/modem_ctl.h
new file mode 100644
index 0000000..7c23165
--- /dev/null
+++ b/devices/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/devices/crespo/nv_data.c b/devices/crespo/nv_data.c
new file mode 100644
index 0000000..f367a3a
--- /dev/null
+++ b/devices/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 "nv_data.h"
+#include "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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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);
+
+ 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/devices/crespo/nv_data.h b/devices/crespo/nv_data.h
new file mode 100644
index 0000000..bc17416
--- /dev/null
+++ b/devices/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