diff options
author | Simon Busch <morphis@gravedo.de> | 2011-08-24 17:29:26 +0200 |
---|---|---|
committer | Simon Busch <morphis@gravedo.de> | 2011-08-24 17:32:13 +0200 |
commit | acce400b447396de34f51b03fb464c3e070deba2 (patch) | |
tree | a746a47e590d683470440f2269429333943d5265 | |
parent | b6ae4aed46ab885604526471417be1a0da72a221 (diff) | |
download | external_libsamsung-ipc-acce400b447396de34f51b03fb464c3e070deba2.zip external_libsamsung-ipc-acce400b447396de34f51b03fb464c3e070deba2.tar.gz external_libsamsung-ipc-acce400b447396de34f51b03fb464c3e070deba2.tar.bz2 |
Add missing source files
-rw-r--r-- | samsung-ipc/devices/crespo/ipc.c | 512 | ||||
-rw-r--r-- | samsung-ipc/devices/crespo/nv_data.c | 353 | ||||
-rw-r--r-- | samsung-ipc/devices/h1/ipc.c | 133 | ||||
-rw-r--r-- | samsung-ipc/ipc.c | 53 | ||||
-rw-r--r-- | samsung-ipc/ipc_util.c | 151 | ||||
-rw-r--r-- | samsung-ipc/test.c | 87 | ||||
-rw-r--r-- | samsung-ipc/util.c | 118 |
7 files changed, 1407 insertions, 0 deletions
diff --git a/samsung-ipc/devices/crespo/ipc.c b/samsung-ipc/devices/crespo/ipc.c new file mode 100644 index 0000000..71db822 --- /dev/null +++ b/samsung-ipc/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/samsung-ipc/devices/crespo/nv_data.c b/samsung-ipc/devices/crespo/nv_data.c new file mode 100644 index 0000000..f367a3a --- /dev/null +++ b/samsung-ipc/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/samsung-ipc/devices/h1/ipc.c b/samsung-ipc/devices/h1/ipc.c new file mode 100644 index 0000000..3959653 --- /dev/null +++ b/samsung-ipc/devices/h1/ipc.c @@ -0,0 +1,133 @@ +/** + * 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.h" + +static int fd = 0; + +int 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 ipc_close() +{ + if(fd) { + return close(fd); + } + + return 1; +} + +void ipc_power_on() +{ + ioctl(fd, IOCTL_PHONE_ON); +} + +void ipc_power_off() +{ + ioctl(fd, IOCTL_PHONE_OFF); +} + +void ipc_send(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); + write(fd, frame, frame_length); + + free(frame); +} + +int ipc_recv(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 = read(fd, buf, sizeof(buf)); + + 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 = read(fd, data, left); + + 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 1; +} + diff --git a/samsung-ipc/ipc.c b/samsung-ipc/ipc.c new file mode 100644 index 0000000..441a130 --- /dev/null +++ b/samsung-ipc/ipc.c @@ -0,0 +1,53 @@ +/** + * 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 <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <radio.h> + +/* Convenience functions for ipc_send */ +inline void ipc_msg_send_get(const int command, unsigned char aseq) +{ + ipc_msg_send(command, IPC_TYPE_GET, 0, 0, aseq); +} + +inline void ipc_msg_send_exec(const int command, unsigned char aseq) +{ + ipc_msg_send(command, IPC_TYPE_EXEC, 0, 0, aseq); +} + +/* Wrapper for ipc_send */ +void ipc_msg_send(const int command, const int type, unsigned char *data, const int length, unsigned char mseq) +{ + struct ipc_request request; + + request.mseq = mseq; + request.aseq = 0xff; + request.group = IPC_GROUP(command); + request.index = IPC_INDEX(command); + request.type = type; + request.length = length; + request.data = data; + + ipc_send(&request); +} + diff --git a/samsung-ipc/ipc_util.c b/samsung-ipc/ipc_util.c new file mode 100644 index 0000000..d497f2f --- /dev/null +++ b/samsung-ipc/ipc_util.c @@ -0,0 +1,151 @@ +/** + * 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 IPC_STR(f) case f: return #f; + +const char *ipc_response_type(struct ipc_response *frame) { + switch(frame->type) { + case IPC_TYPE_INDI: + return "INDI"; + case IPC_TYPE_RESP: + return "RESP"; + case IPC_TYPE_NOTI: + return "NOTI"; + default: + return "UNKNOWN"; + } +} + +const char *ipc_str(struct ipc_response *frame) { + switch(frame->command) { + IPC_STR(IPC_PWR_PHONE_PWR_UP) + IPC_STR(IPC_PWR_PHONE_PWR_OFF) + IPC_STR(IPC_PWR_PHONE_RESET) + IPC_STR(IPC_PWR_BATT_STATUS) + IPC_STR(IPC_PWR_BATT_TYPE) + IPC_STR(IPC_PWR_BATT_COMP) + IPC_STR(IPC_PWR_PHONE_ONLINE) + IPC_STR(IPC_CALL_OUTGOING) + IPC_STR(IPC_CALL_INCOMING) + IPC_STR(IPC_CALL_RELEASE) + IPC_STR(IPC_CALL_ANSWER) + IPC_STR(IPC_CALL_STATUS) + IPC_STR(IPC_CALL_LIST) + IPC_STR(IPC_CALL_BURST_DTMF) + IPC_STR(IPC_CALL_CONT_DTMF) + IPC_STR(IPC_CALL_WAITING) + IPC_STR(IPC_CALL_LINE_ID) + IPC_STR(IPC_SMS_SEND_MSG) + IPC_STR(IPC_SMS_INCOMING_MSG) + IPC_STR(IPC_SMS_READ_MSG) + IPC_STR(IPC_SMS_SAVE_MSG) + IPC_STR(IPC_SMS_DEL_MSG) + IPC_STR(IPC_SMS_DELIVER_REPORT) + IPC_STR(IPC_SMS_DEVICE_READY) + IPC_STR(IPC_SMS_SEL_MEM) + IPC_STR(IPC_SMS_STORED_MSG_COUNT) + IPC_STR(IPC_SMS_SVC_CENTER_ADDR) + IPC_STR(IPC_SMS_SVC_OPTION) + IPC_STR(IPC_SMS_MEM_STATUS) + IPC_STR(IPC_SMS_CBS_MSG) + IPC_STR(IPC_SMS_CBS_CONFIG) + IPC_STR(IPC_SMS_STORED_MSG_STATUS) + IPC_STR(IPC_SMS_PARAM_COUNT) + IPC_STR(IPC_SMS_PARAM) + IPC_STR(IPC_SEC_PIN_STATUS) + IPC_STR(IPC_SEC_PHONE_LOCK) + IPC_STR(IPC_SEC_CHANGE_LOCKING_PW) + IPC_STR(IPC_SEC_SIM_LANG) + IPC_STR(IPC_SEC_RSIM_ACCESS) + IPC_STR(IPC_SEC_GSIM_ACCESS) + IPC_STR(IPC_SEC_SIM_ICC_TYPE) + IPC_STR(IPC_SEC_LOCK_INFO) + IPC_STR(IPC_SEC_ISIM_AUTH) + IPC_STR(IPC_PB_ACCESS) + IPC_STR(IPC_PB_STORAGE) + IPC_STR(IPC_PB_STORAGE_LIST) + IPC_STR(IPC_PB_ENTRY_INFO) + IPC_STR(IPC_PB_CAPABILITY_INFO) + IPC_STR(IPC_DISP_ICON_INFO) + IPC_STR(IPC_DISP_HOMEZONE_INFO) + IPC_STR(IPC_NET_PREF_PLMN) + IPC_STR(IPC_NET_PLMN_SEL) + IPC_STR(IPC_NET_CURRENT_PLMN) + IPC_STR(IPC_NET_PLMN_LIST) + IPC_STR(IPC_NET_REGIST) + IPC_STR(IPC_NET_SUBSCRIBER_NUM) + IPC_STR(IPC_NET_BAND_SEL) + IPC_STR(IPC_NET_SERVICE_DOMAIN_CONFIG) + IPC_STR(IPC_NET_POWERON_ATTACH) + IPC_STR(IPC_NET_MODE_SEL) + IPC_STR(IPC_NET_ACQ_ORDER) + IPC_STR(IPC_NET_IDENTITY) + IPC_STR(IPC_NET_CURRENT_RRC_STATUS) + IPC_STR(IPC_MISC_ME_VERSION) + IPC_STR(IPC_MISC_ME_IMSI) + IPC_STR(IPC_MISC_ME_SN) + IPC_STR(IPC_MISC_TIME_INFO) + IPC_STR(IPC_SS_WAITING) + IPC_STR(IPC_SS_CLI) + IPC_STR(IPC_SS_BARRING) + IPC_STR(IPC_SS_BARRING_PW) + IPC_STR(IPC_SS_FORWARDING) + IPC_STR(IPC_SS_INFO) + IPC_STR(IPC_SS_MANAGE_CALL) + IPC_STR(IPC_SS_USSD) + IPC_STR(IPC_SS_AOC) + IPC_STR(IPC_SS_RELEASE_COMPLETE) + IPC_STR(IPC_GPRS_DEFINE_PDP_CONTEXT) + IPC_STR(IPC_GPRS_QOS) + IPC_STR(IPC_GPRS_PS) + IPC_STR(IPC_GPRS_PDP_CONTEXT) + IPC_STR(IPC_GPRS_SHOW_PDP_ADDR) + IPC_STR(IPC_GPRS_MS_CLASS) + IPC_STR(IPC_GPRS_3G_QUAL_SERVICE_PROFILE) + IPC_STR(IPC_GPRS_IP_CONFIGURATION) + IPC_STR(IPC_GPRS_DEFINE_SEC_PDP_CONTEXT) + IPC_STR(IPC_GPRS_TFT) + IPC_STR(IPC_GPRS_HSDPA_STATUS) + IPC_STR(IPC_GPRS_CURRENT_SESSION_DATA_COUNT) + IPC_STR(IPC_GPRS_DATA_DORMANT) + IPC_STR(IPC_GPRS_DUN_PIN_CTRL) + IPC_STR(IPC_GPRS_CALL_STATUS) + IPC_STR(IPC_SAT_PROFILE_DOWNLOAD) + IPC_STR(IPC_SAT_ENVELOPE_CMD) + IPC_STR(IPC_SAT_PROACTIVE_CMD) + IPC_STR(IPC_SAT_TERMINATE_USAT_SESSION) + IPC_STR(IPC_SAT_EVENT_DOWNLOAD) + IPC_STR(IPC_SAT_PROVIDE_LOCAL_INFO) + IPC_STR(IPC_SAT_POLLING) + IPC_STR(IPC_SAT_REFRESH) + IPC_STR(IPC_SAT_SETUP_EVENT_LIST) + IPC_STR(IPC_SAT_CALL_CONTROL_RESULT) + IPC_STR(IPC_SAT_IMAGE_CLUT) + IPC_STR(IPC_SAT_CALL_PROCESSING) + IPC_STR(IPC_IMEI_START) + IPC_STR(IPC_IMEI_CHECK_DEVICE_INFO) + IPC_STR(IPC_GEN_PHONE_RES) + default: + return "IPC_UNKNOWN"; + } +} + diff --git a/samsung-ipc/test.c b/samsung-ipc/test.c new file mode 100644 index 0000000..b91810d --- /dev/null +++ b/samsung-ipc/test.c @@ -0,0 +1,87 @@ +/** + * 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <radio.h> + +void handle_msg(struct ipc_response *response) +{ + if(response->command == IPC_PWR_PHONE_PWR_UP && + response->type == IPC_TYPE_NOTI) { + printf(">> received PWR_PHONE_ONLINE, requesting IMEI\n"); + + /* h1 requires a short delay for nvram to be available */ + usleep(25000); + ipc_msg_send(IPC_MISC_ME_SN, IPC_TYPE_GET, NULL, 0, 0x42); + } +} + +int main(int argc, char *argv[]) +{ + struct ipc_response response; + int error; + + printf("ipc_open\n"); + error = ipc_open(); + + if(error) { + fprintf(stderr, "ipc_open failed!\n"); + return 1; + } + + printf("ipc_power_on\n"); + ipc_power_on(); + + printf("entering recv loop...\n"); + + while(1) { + error = ipc_recv(&response); + + if(!error) { + printf("%s %s (%u/%u) type=%04x mseq=%02x aseq=%02x\n", + ipc_str(&response), ipc_response_type(&response), + (response.data_length + 7), response.data_length, + response.type, response.mseq, response.aseq); + + hex_dump(response.data, response.data_length); + printf("\n"); + + handle_msg(&response); + + if(response.data) { + free(response.data); + } + } else { + fprintf(stderr, "ipc_recv failed!\n"); + return 1; + } + } + + error = ipc_close(); + + if(error) { + fprintf(stderr, "ipc_close failed!\n"); + return 1; + } + + return 0; +} diff --git a/samsung-ipc/util.c b/samsung-ipc/util.c new file mode 100644 index 0000000..c6dce60 --- /dev/null +++ b/samsung-ipc/util.c @@ -0,0 +1,118 @@ +/** + * 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 <stdio.h> +#include <string.h> +#include <ctype.h> + +#if defined(ANDROID) && !defined(LOG_STDOUT) + +#define LOG_TAG "RIL" +#include <utils/Log.h> +#define printf LOGI + +#endif + +void hex_dump(void *data, int size) +{ + /* dumps size bytes of *data to stdout. Looks like: + * [0000] 75 6E 6B 6E 6F 77 6E 20 + * 30 FF 00 00 00 00 39 00 unknown 0.....9. + * (in a single line of course) + */ + + unsigned char *p = data; + unsigned char c; + int n; + char bytestr[4] = {0}; + char addrstr[10] = {0}; + char hexstr[ 16*3 + 5] = {0}; + char charstr[16*1 + 5] = {0}; + for(n=1;n<=size;n++) { + if (n%16 == 1) { + /* store address for this line */ + snprintf(addrstr, sizeof(addrstr), "%.4x", + ((unsigned int)p-(unsigned int)data) ); + } + + c = *p; + if (isalnum(c) == 0) { + c = '.'; + } + + /* store hex str (for left side) */ + snprintf(bytestr, sizeof(bytestr), "%02X ", *p); + strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); + + /* store char str (for right side) */ + snprintf(bytestr, sizeof(bytestr), "%c", c); + strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); + + if(n%16 == 0) { + /* line completed */ + printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + hexstr[0] = 0; + charstr[0] = 0; + } else if(n%8 == 0) { + /* half line: add whitespaces */ + strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); + strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1); + } + p++; /* next byte */ + } + + if (strlen(hexstr) > 0) { + /* print rest of buffer if not empty */ + printf("[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + } +} + +const char *plmn_lookup(const char *plmn) +{ + unsigned int mcc, mnc; + sscanf(plmn, "%3u%2u", &mcc, &mnc); + + switch(mcc) { + case 204: + switch(mnc) { + case 1: return "VastMobiel"; + case 2: return "Tele2"; + case 4: return "Vodafone"; + case 8: case 10: return "KPN"; + case 12: return "Telfort"; + case 16: case 20: return "T-Mobile"; + } + } + + return NULL; +} + +char *plmn_string(const char *plmn) +{ + int length = (plmn[5] == '#') ? 6 : 7; + + char *plmn_str = (char*)malloc(length); + + memcpy(plmn_str, plmn, length); + plmn_str[length-1] = '\0'; + + return plmn_str; +} + |