diff options
author | Joerie de Gram <j.de.gram@gmail.com> | 2011-10-28 13:38:23 +0200 |
---|---|---|
committer | Joerie de Gram <j.de.gram@gmail.com> | 2011-10-28 13:53:28 +0200 |
commit | 2b9aa23db0b9c0f395abca551414a3c3ecb6d63d (patch) | |
tree | 4a3c066a2f21692cde8f5ce70ef0cc88801a7d72 /samsung-ipc/device | |
parent | 90b3b7de324debfec19829bcd77df5d8b8fba381 (diff) | |
download | external_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.c | 575 | ||||
-rw-r--r-- | samsung-ipc/device/crespo/crespo_ipc.h | 50 | ||||
-rw-r--r-- | samsung-ipc/device/crespo/crespo_modem_ctl.h | 44 | ||||
-rw-r--r-- | samsung-ipc/device/crespo/crespo_nv_data.c | 353 | ||||
-rw-r--r-- | samsung-ipc/device/crespo/crespo_nv_data.h | 37 | ||||
-rw-r--r-- | samsung-ipc/device/h1/h1_ipc.c | 169 | ||||
-rw-r--r-- | samsung-ipc/device/h1/h1_ipc.h | 44 |
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__)); + |