diff options
author | Paul Kocialkowski <contact@paulk.fr> | 2013-07-03 16:10:04 +0200 |
---|---|---|
committer | Paul Kocialkowski <contact@paulk.fr> | 2013-07-03 16:10:04 +0200 |
commit | 10eb92cac26b29c204f3a66fde2f355a692efce8 (patch) | |
tree | 28340036e83e854476b0cf93bba8dd8ffb09fe4f /samsung-ipc/device/xmm6260 | |
parent | eb9cffa5d60cdc037d4a8397e8cc690f00bc4990 (diff) | |
download | hardware_replicant_libsamsung-ipc-10eb92cac26b29c204f3a66fde2f355a692efce8.tar.gz hardware_replicant_libsamsung-ipc-10eb92cac26b29c204f3a66fde2f355a692efce8.tar.bz2 hardware_replicant_libsamsung-ipc-10eb92cac26b29c204f3a66fde2f355a692efce8.zip |
Major rework of xmm6260 common code (MIPI and HSIC) and xmm6260 devices code
Change-Id: I49fba6329824e1f1ab0aceef91a57f75727a41ab
Signed-off-by: Paul Kocialkowski <contact@paulk.fr>
Diffstat (limited to 'samsung-ipc/device/xmm6260')
-rw-r--r-- | samsung-ipc/device/xmm6260/modem.h | 74 | ||||
-rwxr-xr-x | samsung-ipc/device/xmm6260/modem_link_device_hsic.h | 63 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/modem_prj.h | 145 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260.c | 44 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260.h | 46 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_hsic.c | 610 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_hsic.h | 70 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_ipc.c | 399 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_ipc.h | 63 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_loader.c | 104 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_loader.h | 104 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_mipi.c | 675 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_mipi.h | 74 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_modemctl.c | 181 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_modemctl.h | 123 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_sec_modem.c | 500 | ||||
-rw-r--r-- | samsung-ipc/device/xmm6260/xmm6260_sec_modem.h | 60 |
17 files changed, 2340 insertions, 995 deletions
diff --git a/samsung-ipc/device/xmm6260/modem.h b/samsung-ipc/device/xmm6260/modem.h new file mode 100644 index 0000000..5a456f5 --- /dev/null +++ b/samsung-ipc/device/xmm6260/modem.h @@ -0,0 +1,74 @@ +/* + * 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_IF_H__ +#define __MODEM_IF_H__ + +enum modem_t { + IMC_XMM6260, + IMC_XMM6262, + VIA_CBP71, + VIA_CBP72, + SEC_CMC221, + QC_MDM6600, + DUMMY, +}; + +enum dev_format { + IPC_FMT, + IPC_RAW, + IPC_RFS, + IPC_CMD, + IPC_BOOT, + IPC_MULTI_RAW, + IPC_RAMDUMP, + MAX_DEV_FORMAT, +}; +#define MAX_IPC_DEV (IPC_RFS + 1) + +enum modem_io { + IODEV_MISC, + IODEV_NET, + IODEV_DUMMY, +}; + +enum modem_link { + LINKDEV_UNDEFINED, + LINKDEV_MIPI, + LINKDEV_DPRAM, + LINKDEV_SPI, + LINKDEV_USB, + LINKDEV_HSIC, + LINKDEV_C2C, + LINKDEV_MAX, +}; +#define LINKTYPE(modem_link) (1u << (modem_link)) + +enum modem_network { + UMTS_NETWORK, + CDMA_NETWORK, + LTE_NETWORK, +}; + +enum sipc_ver { + NO_SIPC_VER = 0, + SIPC_VER_40 = 40, + SIPC_VER_41 = 41, + SIPC_VER_42 = 42, + SIPC_VER_50 = 50, + MAX_SIPC_VER, +}; + +#endif diff --git a/samsung-ipc/device/xmm6260/modem_link_device_hsic.h b/samsung-ipc/device/xmm6260/modem_link_device_hsic.h new file mode 100755 index 0000000..99e15cf --- /dev/null +++ b/samsung-ipc/device/xmm6260/modem_link_device_hsic.h @@ -0,0 +1,63 @@ +/* + * 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_LINK_DEVICE_USB_H__ +#define __MODEM_LINK_DEVICE_USB_H__ + + +enum { + IF_USB_BOOT_EP = 0, + IF_USB_FMT_EP = 0, + IF_USB_RAW_EP, + IF_USB_RFS_EP, + IF_USB_CMD_EP, + IF_USB_DEVNUM_MAX, +}; + +/* each pipe has 2 ep for in/out */ +#define LINKPM_DEV_NUM (IF_USB_DEVNUM_MAX * 2) +/******************/ +/* xmm6260 specific */ + +#define IOCTL_LINK_CONTROL_ENABLE _IO('o', 0x30) +#define IOCTL_LINK_CONTROL_ACTIVE _IO('o', 0x31) +#define IOCTL_LINK_GET_HOSTWAKE _IO('o', 0x32) +#define IOCTL_LINK_CONNECTED _IO('o', 0x33) +#define IOCTL_LINK_SET_BIAS_CLEAR _IO('o', 0x34) + +/* VID,PID for IMC - XMM6260, XMM6262*/ +#define IMC_BOOT_VID 0x058b +#define IMC_BOOT_PID 0x0041 +#define IMC_MAIN_VID 0x1519 +#define IMC_MAIN_PID 0x0020 +/* VID,PID for STE - M7400 */ +#define STE_BOOT_VID 0x04cc +#define STE_BOOT_PID 0x7400 +#define STE_MAIN_VID 0x04cc +#define STE_MAIN_PID 0x2333 + +enum { + BOOT_DOWN = 0, + IPC_CHANNEL +}; + +enum ch_state { + STATE_SUSPENDED, + STATE_RESUMED, +}; + +#define HOSTWAKE_TRIGLEVEL 0 + +#endif diff --git a/samsung-ipc/device/xmm6260/modem_prj.h b/samsung-ipc/device/xmm6260/modem_prj.h index df4c37d..99f6087 100644 --- a/samsung-ipc/device/xmm6260/modem_prj.h +++ b/samsung-ipc/device/xmm6260/modem_prj.h @@ -13,14 +13,26 @@ * */ +#include <stdbool.h> +#include <stdint.h> +#include <linux/types.h> + +#define u8 uint8_t +#define u16 uint16_t +#define u32 uint32_t +#define u64 uint64_t + #ifndef __MODEM_PRJ_H__ #define __MODEM_PRJ_H__ -#include <stdint.h> +#define MAX_CPINFO_SIZE 512 #define MAX_LINK_DEVTYPE 3 -#define MAX_RAW_DEVS 32 -#define MAX_NUM_IO_DEV (MAX_RAW_DEVS + 4) + +#define MAX_FMT_DEVS 10 +#define MAX_RAW_DEVS 32 +#define MAX_RFS_DEVS 10 +#define MAX_NUM_IO_DEV (MAX_FMT_DEVS + MAX_RAW_DEVS + MAX_RFS_DEVS) #define IOCTL_MODEM_ON _IO('o', 0x19) #define IOCTL_MODEM_OFF _IO('o', 0x20) @@ -33,7 +45,7 @@ #define IOCTL_MODEM_PROTOCOL_RESUME _IO('o', 0x26) #define IOCTL_MODEM_STATUS _IO('o', 0x27) -#define IOCTL_MODEM_GOTA_START _IO('o', 0x28) +#define IOCTL_MODEM_DL_START _IO('o', 0x28) #define IOCTL_MODEM_FW_UPDATE _IO('o', 0x29) #define IOCTL_MODEM_NET_SUSPEND _IO('o', 0x30) @@ -72,10 +84,76 @@ #define PSD_DATA_CHID_BEGIN 0x2A #define PSD_DATA_CHID_END 0x38 +#define PS_DATA_CH_0 10 +#define PS_DATA_CH_LAST 24 + #define IP6VERSION 6 #define SOURCE_MAC_ADDR {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC} +/* Debugging features */ +#define MAX_MIF_LOG_PATH_LEN 128 +#define MAX_MIF_LOG_FILE_SIZE 0x800000 /* 8 MB */ + +#define MAX_MIF_EVT_BUFF_SIZE 256 +#define MAX_MIF_TIME_LEN 32 +#define MAX_MIF_NAME_LEN 16 +#define MAX_MIF_STR_LEN 127 +#define MAX_MIF_LOG_LEN 128 + +enum mif_event_id { + MIF_IRQ_EVT = 0, + MIF_LNK_RX_EVT, + MIF_MUX_RX_EVT, + MIF_IOD_RX_EVT, + MIF_IOD_TX_EVT, + MIF_MUX_TX_EVT, + MIF_LNK_TX_EVT, + MAX_MIF_EVT +}; + +struct dpram_queue_status { + unsigned in; + unsigned out; +}; + +struct dpram_queue_status_pair { + struct dpram_queue_status txq; + struct dpram_queue_status rxq; +}; + +struct dpram_irq_buff { + unsigned magic; + unsigned access; + struct dpram_queue_status_pair qsp[MAX_IPC_DEV]; + unsigned int2ap; + unsigned int2cp; +}; + +struct mif_event_buff { + char time[MAX_MIF_TIME_LEN]; + + struct timeval tv; + enum mif_event_id evt; + + char mc[MAX_MIF_NAME_LEN]; + + char iod[MAX_MIF_NAME_LEN]; + + char ld[MAX_MIF_NAME_LEN]; + enum modem_link link_type; + + unsigned rcvd; + unsigned len; + union { + u8 data[MAX_MIF_LOG_LEN]; + struct dpram_irq_buff dpram_irqb; + }; +}; + +#define MIF_LOG_DIR "/sdcard" +#define MIF_LOG_LV_FILE "/data/.mif_log_level" + /* Does modem ctl structure will use state ? or status defined below ?*/ enum modem_state { STATE_OFFLINE, @@ -85,6 +163,8 @@ enum modem_state { STATE_ONLINE, STATE_NV_REBUILDING, /* <= rebuilding start */ STATE_LOADER_DONE, + STATE_SIM_ATTACH, + STATE_SIM_DETACH, }; enum com_state { @@ -95,6 +175,25 @@ enum com_state { COM_CRASH, }; +enum link_mode { + LINK_MODE_INVALID = 0, + LINK_MODE_IPC, + LINK_MODE_BOOT, + LINK_MODE_DLOAD, + LINK_MODE_ULOAD, +}; + +struct sim_state { + bool online; /* SIM is online? */ + bool changed; /* online is changed? */ +}; + +#define HDLC_START 0x7F +#define HDLC_END 0x7E +#define SIZE_OF_HDLC_START 1 +#define SIZE_OF_HDLC_END 1 +#define MAX_LINK_PADDING_SIZE 3 + struct header_data { char hdr[HDLC_HEADER_MAX_SIZE]; unsigned len; @@ -102,26 +201,30 @@ struct header_data { char start; /*hdlc start header 0x7F*/ }; -struct sipc4_hdlc_fmt_hdr { - uint16_t len; - uint8_t control; +struct fmt_hdr { + u16 len; + u8 control; } __attribute__((packed)); -struct sipc4_fmt_hdr { - uint16_t len; - uint8_t msg_seq; - uint8_t ack_seq; - uint8_t main_cmd; - uint8_t sub_cmd; - uint8_t cmd_type; +struct raw_hdr { + u32 len; + u8 channel; + u8 control; } __attribute__((packed)); -//Link control +struct rfs_hdr { + u32 len; + u8 cmd; + u8 id; +} __attribute__((packed)); -#define IOCTL_LINK_CONTROL_ENABLE _IO('o', 0x30) -#define IOCTL_LINK_CONTROL_ACTIVE _IO('o', 0x31) -#define IOCTL_LINK_GET_HOSTWAKE _IO('o', 0x32) -#define IOCTL_LINK_CONNECTED _IO('o', 0x33) -#define IOCTL_LINK_SET_BIAS_CLEAR _IO('o', 0x34) +struct sipc_fmt_hdr { + u16 len; + u8 msg_seq; + u8 ack_seq; + u8 main_cmd; + u8 sub_cmd; + u8 cmd_type; +} __attribute__((packed)); -#endif //__MODEM_PRJ_H__ +#endif diff --git a/samsung-ipc/device/xmm6260/xmm6260.c b/samsung-ipc/device/xmm6260/xmm6260.c new file mode 100644 index 0000000..a5c0779 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260.c @@ -0,0 +1,44 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <sys/ioctl.h> + +#include "xmm6260.h" + +unsigned char xmm6260_crc_calculate(void *buffer, int length) +{ + unsigned char crc; + unsigned char *p; + + if (buffer == NULL || length <= 0) + return 0; + + p = (unsigned char *) buffer; + + crc = 0; + while (length--) + crc ^= *p++; + + return crc; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260.h b/samsung-ipc/device/xmm6260/xmm6260.h new file mode 100644 index 0000000..d56ad1d --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260.h @@ -0,0 +1,46 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __XMM6260_H__ +#define __XMM6260_H__ + +#define XMM6260_AT "ATAT" +#define XMM6260_PSI_PADDING 0xFF +#define XMM6260_PSI_MAGIC 0x30 +#define XMM6260_SEC_END_MAGIC 0x0000 +#define XMM6260_HW_RESET_MAGIC 0x111001 +#define XMM6260_DATA_SIZE 0x1000 + +#define XMM6260_COMMAND_SET_PORT_CONFIG 0x86 +#define XMM6260_COMMAND_SEC_START 0x204 +#define XMM6260_COMMAND_SEC_END 0x205 +#define XMM6260_COMMAND_HW_RESET 0x208 +#define XMM6260_COMMAND_FLASH_SET_ADDRESS 0x802 +#define XMM6260_COMMAND_FLASH_WRITE_BLOCK 0x804 + +#define XMM6260_FIRMWARE_ADDRESS 0x60300000 +#define XMM6260_NV_DATA_ADDRESS 0x60E80000 +#define XMM6260_MPS_DATA_ADDRESS 0x61080000 + +unsigned char xmm6260_crc_calculate(void *buffer, int length); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_hsic.c b/samsung-ipc/device/xmm6260/xmm6260_hsic.c new file mode 100644 index 0000000..263934b --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_hsic.c @@ -0,0 +1,610 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> + * + * Based on the incomplete C++ implementation which is: + * Copyright (C) 2012 Sergey Gridasov <grindars@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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/select.h> + +#include <samsung-ipc.h> +#include <util.h> + +#include "xmm6260.h" +#include "xmm6260_hsic.h" + +int xmm6260_hsic_ack_read(int device_fd, unsigned short ack) +{ + struct timeval timeout; + fd_set fds; + + unsigned short value; + int rc; + int i; + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + for (i = 0; i < 50; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + return -1; + + value = 0; + rc = read(device_fd, &value, sizeof(value)); + if (rc < (int) sizeof(value)) + continue; + + if (value == ack) + return 0; + } + + return -1; +} + +int xmm6260_hsic_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size) +{ + struct xmm6260_hsic_psi_header psi_header; + char at[] = XMM6260_AT; + unsigned char psi_ack; + unsigned char chip_id; + unsigned char psi_crc; + + struct timeval timeout; + fd_set fds; + int wc; + + unsigned char *p; + int length; + int rc; + int i; + + if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0) + return -1; + + FD_ZERO(&fds); + + i = 0; + length = strlen(at); + + do { + FD_SET(device_fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + rc = write(device_fd, at, length); + if (rc < length) { + ipc_client_log(client, "Writing ATAT in ASCII failed"); + goto error; + } + ipc_client_log(client, "Wrote ATAT in ASCII"); + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc < 0) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + + if (i++ > 50) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + } while(rc == 0); + + FD_SET(device_fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading chip id failed"); + goto error; + } + + psi_ack = 0; + rc = read(device_fd, &psi_ack, sizeof(psi_ack)); + if (rc < 0 || psi_ack != XMM6260_HSIC_BOOT0_ACK) { + ipc_client_log(client, "Reading boot ACK failed"); + goto error; + } + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading chip id failed"); + goto error; + } + + chip_id = 0; + rc = read(device_fd, &chip_id, sizeof(chip_id)); + if (rc < 0) { + ipc_client_log(client, "Reading chip id failed"); + goto error; + } + ipc_client_log(client, "Read chip id (0x%x)", chip_id); + + psi_header.magic = XMM6260_PSI_MAGIC; + psi_header.length = psi_size; + psi_header.padding = XMM6260_PSI_PADDING; + + rc = write(device_fd, &psi_header, sizeof(psi_header)); + if (rc < (int) sizeof(psi_header)) { + ipc_client_log(client, "Writing PSI header failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI header"); + + p = (unsigned char *) psi_data; + + wc = 0; + while (wc < psi_size) { + rc = write(device_fd, (void *) p, psi_size - wc); + if (rc < 0) { + ipc_client_log(client, "Writing PSI failed"); + goto error; + } + + p += rc; + wc += rc; + } + + psi_crc = xmm6260_crc_calculate(psi_data, psi_size); + + ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc); + + rc = write(device_fd, &psi_crc, sizeof(psi_crc)); + if (rc < (int) sizeof(psi_crc)) { + ipc_client_log(client, "Writing PSI CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + for (i = 0; i < XMM6260_HSIC_PSI_UNKNOWN_COUNT; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading PSI unknown failed"); + goto error; + } + + rc = read(device_fd, &psi_ack, sizeof(psi_ack)); + if (rc < (int) sizeof(psi_ack)) { + ipc_client_log(client, "Reading PSI unknown failed"); + goto error; + } + } + + for (i = 0; i < XMM6260_HSIC_PSI_CRC_ACK_COUNT ; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) { + ipc_client_log(client, "Reading PSI CRC ACK failed"); + goto error; + } + + rc = read(device_fd, &psi_ack, sizeof(psi_ack)); + if (rc < (int) sizeof(psi_ack) || psi_ack != XMM6260_HSIC_PSI_CRC_ACK) { + ipc_client_log(client, "Reading PSI CRC ACK failed"); + goto error; + } + } + ipc_client_log(client, "Read PSI CRC ACK"); + + rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_PSI_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading PSI ACK failed"); + goto error; + } + ipc_client_log(client, "Read PSI ACK"); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_hsic_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size) +{ + unsigned char ebl_crc; + + int chunk; + int count; + int wc; + + unsigned char *p; + int length; + int rc; + + if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size <= 0) + return -1; + + length = sizeof(ebl_size); + + rc = write(device_fd, &ebl_size, length); + if (rc < length) { + ipc_client_log(client, "Writing EBL size failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL size"); + + rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_EBL_SIZE_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL size ACK failed"); + goto error; + } + + p = (unsigned char *) ebl_data; + + chunk = XMM6260_HSIC_EBL_CHUNK; + wc = 0; + while (wc < ebl_size) { + count = chunk < ebl_size - wc ? chunk : ebl_size - wc; + + rc = write(device_fd, (void *) p, count); + if (rc < 0) { + ipc_client_log(client, "Writing EBL failed"); + goto error; + } + + p += rc; + wc += rc; + } + + ebl_crc = xmm6260_crc_calculate(ebl_data, ebl_size); + + ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc); + + rc = write(device_fd, &ebl_crc, sizeof(ebl_crc)); + if (rc < (int) sizeof(ebl_crc)) { + ipc_client_log(client, "Writing EBL CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc); + + rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_EBL_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL ACK failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_hsic_command_send(int device_fd, unsigned short code, + void *data, int size, int command_data_size, int ack) +{ + struct xmm6260_hsic_command_header header; + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + + unsigned char *p; + int rc; + int i; + + if (device_fd < 0 || data == NULL || size <= 0 || command_data_size < size) + return -1; + + header.checksum = (size & 0xffff) + code; + header.code = code; + header.data_size = size; + + p = (unsigned char *) data; + + for (i = 0; i < size; i++) + header.checksum += *p++; + + length = command_data_size + sizeof(header); + buffer = malloc(length); + + memset(buffer, 0, length); + p = (unsigned char *) buffer; + memcpy(p, &header, sizeof(header)); + p += sizeof(header); + memcpy(p, data, size); + + rc = write(device_fd, buffer, length); + if (rc < length) + goto error; + + if (!ack) { + rc = 0; + goto complete; + } + + memset(buffer, 0, length); + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, &header, sizeof(header)); + if (rc < (int) sizeof(header)) + goto error; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, buffer, command_data_size); + if (rc < command_data_size) + goto error; + + if (header.code != code) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_hsic_modem_data_send(int device_fd, void *data, int size, int address) +{ + int chunk; + int count; + int c; + + unsigned char *p; + int rc; + + if (device_fd < 0 || data == NULL || size <= 0) + return -1; + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), XMM6260_HSIC_FLASH_SET_ADDRESS_SIZE, 1); + if (rc < 0) + goto error; + + p = (unsigned char *) data; + + chunk = XMM6260_HSIC_MODEM_DATA_CHUNK; + c = 0; + while (c < size) { + count = chunk < size - c ? chunk : size - c; + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_FLASH_WRITE_BLOCK, p, count, XMM6260_HSIC_FLASH_WRITE_BLOCK_SIZE, 0); + if (rc < 0) + goto error; + + p += count; + c += count; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_hsic_port_config_send(struct ipc_client *client, int device_fd) +{ + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + length = XMM6260_HSIC_PORT_CONFIG_SIZE; + buffer = malloc(length); + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, buffer, length); + if (rc < length) { + ipc_client_log(client, "Reading port config failed"); + goto error; + } + ipc_client_log(client, "Read port config"); + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SET_PORT_CONFIG, buffer, length, XMM6260_HSIC_SET_PORT_CONFIG_SIZE, 1); + if (rc < 0) { + ipc_client_log(client, "Sending port config command failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_hsic_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size <= 0) + return -1; + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SEC_START, sec_data, sec_size, XMM6260_HSIC_SEC_START_SIZE, 1); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_hsic_sec_end_send(struct ipc_client *client, int device_fd) +{ + unsigned short sec_data; + int sec_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + sec_data = XMM6260_SEC_END_MAGIC; + sec_size = sizeof(sec_data); + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SEC_END, &sec_data, sec_size, XMM6260_HSIC_SEC_END_SIZE, 1); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_hsic_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size <= 0) + return -1; + + rc = xmm6260_hsic_modem_data_send(device_fd, firmware_data, firmware_size, XMM6260_FIRMWARE_ADDRESS); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_hsic_nv_data_send(struct ipc_client *client, int device_fd) +{ + void *nv_data = NULL; + int nv_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + rc = nv_data_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data"); + + rc = nv_data_md5_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data md5 failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data md5"); + + nv_data = file_data_read(nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); + if (nv_data == NULL) { + ipc_client_log(client, "Reading nv_data failed"); + goto error; + } + ipc_client_log(client, "Read nv_data"); + + nv_size = nv_data_size(client); + + rc = xmm6260_hsic_modem_data_send(device_fd, nv_data, nv_size, XMM6260_NV_DATA_ADDRESS); + if (rc < 0) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (nv_data != NULL) + free(nv_data); + + return rc; +} + +int xmm6260_hsic_hw_reset_send(struct ipc_client *client, int device_fd) +{ + unsigned int hw_reset_data; + int hw_reset_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + hw_reset_data = XMM6260_HW_RESET_MAGIC; + hw_reset_size = sizeof(hw_reset_data); + + rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, XMM6260_HSIC_HW_RESET_SIZE, 0); + if (rc < 0) + return -1; + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_hsic.h b/samsung-ipc/device/xmm6260/xmm6260_hsic.h new file mode 100644 index 0000000..5032e41 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_hsic.h @@ -0,0 +1,70 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __XMM6260_HSIC_H__ +#define __XMM6260_HSIC_H__ + +#define XMM6260_HSIC_BOOT0_ACK 0xF0 +#define XMM6260_HSIC_PSI_UNKNOWN_COUNT 22 +#define XMM6260_HSIC_PSI_CRC_ACK 0x01 +#define XMM6260_HSIC_PSI_CRC_ACK_COUNT 2 +#define XMM6260_HSIC_PSI_ACK 0xAA00 +#define XMM6260_HSIC_EBL_SIZE_ACK 0xCCCC +#define XMM6260_HSIC_EBL_ACK 0xA551 +#define XMM6260_HSIC_EBL_CHUNK 0x4000 +#define XMM6260_HSIC_PORT_CONFIG_SIZE 0x4C +#define XMM6260_HSIC_SET_PORT_CONFIG_SIZE 0x800 +#define XMM6260_HSIC_SEC_START_SIZE 0x4000 +#define XMM6260_HSIC_SEC_END_SIZE 0x4000 +#define XMM6260_HSIC_HW_RESET_SIZE 0x4000 +#define XMM6260_HSIC_FLASH_SET_ADDRESS_SIZE 0x4000 +#define XMM6260_HSIC_FLASH_WRITE_BLOCK_SIZE 0x4000 +#define XMM6260_HSIC_MODEM_DATA_CHUNK 0x4000 + +struct xmm6260_hsic_psi_header { + unsigned char magic; + unsigned short length; + unsigned char padding; +} __attribute__((packed)); + +struct xmm6260_hsic_command_header { + unsigned short checksum; + unsigned short code; + unsigned int data_size; +} __attribute__((packed)); + +int xmm6260_hsic_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size); +int xmm6260_hsic_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size); + +int xmm6260_hsic_port_config_send(struct ipc_client *client, int device_fd); +int xmm6260_hsic_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size); +int xmm6260_hsic_sec_end_send(struct ipc_client *client, int device_fd); +int xmm6260_hsic_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size); +int xmm6260_hsic_nv_data_send(struct ipc_client *client, int device_fd); +int xmm6260_hsic_hw_reset_send(struct ipc_client *client, int device_fd); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_ipc.c b/samsung-ipc/device/xmm6260/xmm6260_ipc.c deleted file mode 100644 index b8c1f60..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_ipc.c +++ /dev/null @@ -1,399 +0,0 @@ -/** - * This file is part of libsamsung-ipc. - * - * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> - * Copyright (C) 2011 Paul Kocialkowski <contact@paulk.fr> - * based on crespo IPC code which is: - * - * 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 2 of the License, or - * (at your option) any later version. - * - * libsamsung-ipc is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <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 <samsung-ipc.h> - -#include "ipc.h" - -#include "xmm6260_ipc.h" -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -int xmm6260_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) -{ - struct ipc_header *hdr; - unsigned char *frame; - unsigned char *payload; - size_t frame_length; - - /* Frame IPC header + payload length */ - frame_length = (sizeof(*hdr) + request->length); - - frame = (unsigned char*)malloc(frame_length); - hdr = (struct ipc_header*)frame; - - /* IPC header */ - hdr->length = frame_length; - hdr->mseq = request->mseq; - hdr->aseq = request->aseq; - hdr->group = request->group; - hdr->index = request->index; - hdr->type = request->type; - - /* IPC payload */ - payload = (frame + sizeof(*hdr)); - memcpy(payload, request->data, request->length); - - ipc_client_log_send(client, request, __func__); - - client->handlers->write(client->handlers->transport_data, frame, frame_length); - - free(frame); - - return 0; -} - -int xmm6260_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) -{ - unsigned char buf[IPC_MAX_XFER] = {}; - unsigned char *data; - unsigned short *frame_length; - - struct ipc_header ipc = { - .length = 0, - }; - - int num_read = 0; - int left = 0; - - if (!client || !response) - return -1; - - num_read = client->handlers->read(client->handlers->transport_data, buf, IPC_MAX_XFER); - - if (num_read <= 0) { - ipc_client_log(client, "read failed to read ipc length: %d", num_read); - response->data = 0; - response->length = 0; - goto done; - } - - memcpy(&ipc, buf, sizeof(ipc)); - left = ipc.length - num_read; - - if (left > 0) - num_read = client->handlers->read(client->handlers->transport_data, buf + num_read, left); - - memcpy(&ipc, buf, sizeof(ipc)); - - response->mseq = ipc.mseq; - response->aseq = ipc.aseq; - response->group = ipc.group; - response->index = ipc.index; - response->type = ipc.type; - response->cmd = IPC_COMMAND(response); - response->length = ipc.length - sizeof(ipc); - response->data = NULL; - - if (response->length > 0) { - response->data = (unsigned char*)malloc(response->length); - memcpy(response->data, buf + sizeof(ipc), response->length); - } - - ipc_client_log_recv(client, response, __func__); - -done: - return 0; -} - -int xmm6260_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) -{ - unsigned char buf[IPC_MAX_XFER] = {}; - struct rfs_hdr header; - int header_recv = 0; - unsigned count=0; - int rc; - int ret = 0; - - do { - rc = client->handlers->read(client->handlers->transport_data, buf, IPC_MAX_XFER); - - if (rc < 0) { - ipc_client_log(client, "Failed to read RFS data."); - ret = -1; - goto done; - } - - // We didn't recieve the header yet - if (!header_recv) { - if ((unsigned) rc < sizeof(struct rfs_hdr)) { - ipc_client_log(client, "Failed to read RFS data."); - ret = -1; - goto done; - } - - memcpy((void *) &header, (void *) buf, sizeof(struct rfs_hdr)); - - if (header.size < sizeof(struct rfs_hdr)) { - ipc_client_log(client, "Invalid size in header"); - ret = -1; - goto done; - } - - response->mseq = 0; - response->aseq = header.id; - response->group = IPC_GROUP_RFS; - response->index = header.cmd; - response->type = 0; - response->length = header.size - sizeof(struct rfs_hdr); - response->data = NULL; - - if (response->length > 0) { - response->data = malloc(response->length); - memcpy(response->data, - (void *) (buf + sizeof(struct rfs_hdr)), - rc - sizeof(struct rfs_hdr)); - } - - header_recv = 1; - } else { - // Still reading data, with no header - memcpy((void *) (response->data + count - sizeof(struct rfs_hdr)), buf, rc); - } - - count += rc; - } while (count < header.size); - - ipc_client_log_recv(client, response, __func__); - -done: - return ret; -} - -int xmm6260_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) -{ - struct rfs_hdr *header = NULL; - char *data = NULL; - int data_length; - int rc; - - data_length = sizeof(struct rfs_hdr) + request->length; - data = malloc(data_length); - memset(data, 0, data_length); - - header = (struct rfs_hdr *) data; - header->id = request->mseq; - header->cmd = request->index; - header->size = data_length; - - memcpy((void *) (data + sizeof(struct rfs_hdr)), request->data, request->length); - - ipc_client_log_send(client, request, __func__); - - rc = client->handlers->write(client->handlers->transport_data, data, data_length); - - return rc; -} - -int xmm6260_ipc_open(void *transport_data, int type) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - switch(type) - { - case IPC_CLIENT_TYPE_FMT: - fd = open("/dev/umts_ipc0", O_RDWR | O_NOCTTY | O_NONBLOCK); - break; - case IPC_CLIENT_TYPE_RFS: - fd = open("/dev/umts_rfs0", O_RDWR | O_NOCTTY | O_NONBLOCK); - break; - default: - break; - } - - if(fd < 0) - return -1; - - data->fd = fd; - - return 0; -} - -int xmm6260_ipc_close(void *transport_data) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if (fd < 0) - return -1; - - close(fd); - - return 0; -} - -int xmm6260_ipc_read(void *transport_data, void *buffer, unsigned int length) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - int rc; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if(fd < 0) - return -1; - - rc = expect(fd, 100); - if (rc < 0) - return -1; - - rc = read(fd, buffer, length); - if(rc < 0) - return -1; - - return rc; -} - -int xmm6260_ipc_write(void *transport_data, void *buffer, unsigned int length) -{ - struct xmm6260_ipc_transport_data *data; - int fd; - int rc; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if(fd < 0) - return -1; - - rc = write(fd, buffer, length); - if(rc < 0) - return -1; - - return rc; -} - -int xmm6260_ipc_poll(void *transport_data, struct timeval *timeout) -{ - struct xmm6260_ipc_transport_data *data; - fd_set fds; - int fd; - int rc; - - if (transport_data == NULL) - return -1; - - data = (struct xmm6260_ipc_transport_data *) transport_data; - - fd = data->fd; - if (fd < 0) - return -1; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - - rc = select(FD_SETSIZE, &fds, NULL, NULL, timeout); - return rc; -} - -int xmm6260_ipc_power_on(void *power_data) -{ - return 0; -} - -int xmm6260_ipc_power_off(void *power_data) -{ - return 0; -} - -int xmm6260_ipc_data_create(void **transport_data, void **power_data, void **gprs_data) -{ - if (transport_data == NULL) - return -1; - - *transport_data = (void *) malloc(sizeof(struct xmm6260_ipc_transport_data)); - memset(*transport_data, 0, sizeof(struct xmm6260_ipc_transport_data)); - - return 0; -} - -int xmm6260_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data) -{ - if (transport_data == NULL) - return -1; - - free(transport_data); - - return 0; -} - -char *xmm6260_ipc_gprs_get_iface(int cid) -{ - char *iface = NULL; - - if(cid > GPRS_IFACE_COUNT) - return NULL; - - asprintf(&iface, "%s%d", GPRS_IFACE_PREFIX, cid - 1); - - return iface; -} - -int xmm6260_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) -{ - if (capabilities == NULL) - return -1; - - capabilities->port_list = 1; - capabilities->cid_max = GPRS_IFACE_COUNT; - - return 0; -} - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_ipc.h b/samsung-ipc/device/xmm6260/xmm6260_ipc.h deleted file mode 100644 index 632c300..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_ipc.h +++ /dev/null @@ -1,63 +0,0 @@ -/** - * This file is part of libsamsung-ipc. - * - * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> - * Copyright (C) 2011 Paul Kocialkowski <contact@paulk.fr> - * based on crespo IPC code which is: - * - * 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 2 of the License, or - * (at your option) any later version. - * - * libsamsung-ipc is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdint.h> - -#ifndef __XMM6260_IPC_H__ -#define __XMM6260_IPC_H__ - -#define IPC_MAX_XFER 4096 -#define GPRS_IFACE_PREFIX "rmnet" -#define GPRS_IFACE_COUNT 3 - -struct rfs_hdr { - uint32_t size; - uint8_t cmd; - uint8_t id; -} __attribute__ ((packed)); - -int xmm6260_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request); -int xmm6260_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response); -int xmm6260_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response); -int xmm6260_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request); -int xmm6260_ipc_open(void *transport_data, int type); -int xmm6260_ipc_close(void *transport_data); -int xmm6260_ipc_read(void *transport_data, void *buffer, unsigned int length); -int xmm6260_ipc_write(void *transport_data, void *buffer, unsigned int length); -int xmm6260_ipc_poll(void *transport_data, struct timeval *timeout); -int xmm6260_ipc_power_on(void *power_data); -int xmm6260_ipc_power_off(void *power_data); -int xmm6260_ipc_data_create(void **transport_data, void **power_data, void **gprs_data); -int xmm6260_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data); -char* xmm6260_ipc_gprs_get_iface(int cid); -int xmm6260_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities); - -struct xmm6260_ipc_transport_data { - int fd; -}; - -#endif - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_loader.c b/samsung-ipc/device/xmm6260/xmm6260_loader.c deleted file mode 100644 index 0c077c6..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_loader.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * XMM6260 Firmware loader functions - * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> - * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr> - * - * based on the incomplete C++ implementation which is - * Copyright (C) 2012 Sergey Gridasov <grindars@gmail.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> - -#include <getopt.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/ioctl.h> - -#include <sys/time.h> - -#include <sys/mman.h> -#include <sys/stat.h> - -#include "ipc.h" - -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -unsigned char xmm6260_crc_calculate(void* data, size_t offset, size_t length) -{ - unsigned char crc = 0; - unsigned char *ptr = (unsigned char*) (data + offset); - - while (length--) - crc ^= *ptr++; - - return crc; -} - -int expect(int fd, unsigned timeout) -{ - int ret = 0; - - struct timeval tv = { - tv.tv_sec = timeout / 1000, - tv.tv_usec = 1000 * (timeout % 1000), - }; - - fd_set read_set; - FD_ZERO(&read_set); - FD_SET(fd, &read_set); - - ret = select(fd + 1, &read_set, 0, 0, &tv); - - if (ret < 0) - goto fail; - - if (ret < 1 || !FD_ISSET(fd, &read_set)) - goto fail; - -fail: - return ret; -} - -int expect_read(int fd, void *buf, size_t size) -{ - int ret; - - if ((ret = expect(fd, DEFAULT_TIMEOUT)) < 1) - return ret; - - return read(fd, buf, size); -} - -int expect_data(int fd, void *data, size_t size) -{ - int ret; - char buf[size]; - - if ((ret = expect_read(fd, buf, size)) != size) { - ret = -1; - return ret; - } - - ret = memcmp(buf, data, size); - - return ret; -} diff --git a/samsung-ipc/device/xmm6260/xmm6260_loader.h b/samsung-ipc/device/xmm6260/xmm6260_loader.h deleted file mode 100644 index 9f19068..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_loader.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * XMM6260 Firmware loader functions - * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> - * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr> - * - * based on the incomplete C++ implementation which is - * Copyright (C) 2012 Sergey Gridasov <grindars@gmail.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __XMM6260_LOADER_H__ -#define __XMM6260_LOADER_H__ - -#define RADIO_MAP_SIZE (16 << 20) -#define DEFAULT_TIMEOUT 50 - -/* - * Offset and length to describe a part of XMM6260 firmware - */ -struct xmm6260_radio_part { - size_t offset; - size_t length; -}; - -/* - * Components of the Samsung XMM6260 firmware - */ -enum xmm6260_image { - PSI, - EBL, - SECURE_IMAGE, - FIRMWARE, - NVDATA, -}; - -/* - * Bootloader control interface definitions - */ -enum xmm6260_boot_cmd { - SetPortConf, - - ReqSecStart, - ReqSecEnd, - ReqForceHwReset, - - ReqFlashSetAddress, - ReqFlashWriteBlock, -}; - -/* - * @brief Calculate the checksum for the XMM6260 bootloader protocol - * - * @param data [in] the data to calculate the checksum for - * @param offset [in] number of bytes to skip - * @param length [in] length of data in bytes - * @return checksum value - */ -unsigned char xmm6260_crc_calculate(void* data, size_t offset, size_t length); - -/* - * @brief Waits for fd to become available for reading - * - * @param fd [in] File descriptor of the socket - * @param timeout [in] Timeout in milliseconds - * @return Negative value indicating error code - * @return Available socket number - 1, as select() - */ -int expect(int fd, unsigned timeout); - -/* - * @brief Waits for data available and reads it to the buffer - * - * @param fd [in] File descriptor of the socket - * @param buf Buffer to hold data - * @param size [in] The number of bytes to read - * @return Negative value indicating error code - * @return The size of data received - */ -int expect_read(int fd, void *buf, size_t size); - -/* - * @brief Receives data and compares with the pattern in memory - * - * @param fd [in] File descriptor of the socket - * @param data [in] The pattern to compare to - * @param size [in] The length of data to read in bytes - * @return Negative value indicating error code - * @return Available socket number - 1, as select() - */ -int expect_data(int fd, void *data, size_t size); - -#endif diff --git a/samsung-ipc/device/xmm6260/xmm6260_mipi.c b/samsung-ipc/device/xmm6260/xmm6260_mipi.c new file mode 100644 index 0000000..902b7b9 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_mipi.c @@ -0,0 +1,675 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> + * + * Based on the incomplete C++ implementation which is: + * Copyright (C) 2012 Sergey Gridasov <grindars@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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <sys/select.h> + +#include <samsung-ipc.h> +#include <util.h> + +#include "xmm6260.h" +#include "xmm6260_mipi.h" + +int xmm6260_mipi_crc_calculate(void *buffer, int length) +{ + unsigned char crc; + int mipi_crc; + + crc = xmm6260_crc_calculate(buffer, length); + mipi_crc = (crc << 24) | 0xffffff; + + return mipi_crc; +} + +int xmm6260_mipi_ack_read(int device_fd, unsigned short ack) +{ + struct timeval timeout; + fd_set fds; + + unsigned int value; + int rc; + int i; + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + for (i = 0; i < 50; i++) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + return -1; + + value = 0; + rc = read(device_fd, &value, sizeof(value)); + if (rc < (int) sizeof(value)) + continue; + + if ((value & 0xffff) == ack) + return 0; + } + + return -1; +} + +int xmm6260_mipi_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size) +{ + struct xmm6260_mipi_psi_header psi_header; + char at[] = XMM6260_AT; + int psi_crc; + + struct timeval timeout; + fd_set fds; + int wc; + + unsigned char *p; + int length; + int rc; + int i; + + if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0) + return -1; + + FD_ZERO(&fds); + + i = 0; + length = strlen(at); + + do { + FD_SET(device_fd, &fds); + + timeout.tv_sec = 0; + timeout.tv_usec = 100000; + + rc = write(device_fd, at, length); + if (rc < length) { + ipc_client_log(client, "Writing ATAT in ASCII failed"); + goto error; + } + ipc_client_log(client, "Wrote ATAT in ASCII"); + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc < 0) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + + if (i++ > 50) { + ipc_client_log(client, "Waiting for bootup failed"); + goto error; + } + } while(rc == 0); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_BOOT0_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading boot ACK failed"); + goto error; + } + + psi_header.padding = XMM6260_PSI_PADDING; + psi_header.length = ((psi_size >> 8) & 0xff) | ((psi_size & 0xff) << 8); + psi_header.magic = XMM6260_PSI_MAGIC; + + rc = write(device_fd, &psi_header, sizeof(psi_header)); + if (rc < (int) sizeof(psi_header)) { + ipc_client_log(client, "Writing PSI header failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI header"); + + p = (unsigned char *) psi_data; + + wc = 0; + while (wc < psi_size) { + rc = write(device_fd, (void *) p, psi_size - wc); + if (rc < 0) { + ipc_client_log(client, "Writing PSI failed"); + goto error; + } + + p += rc; + wc += rc; + } + + psi_crc = xmm6260_mipi_crc_calculate(psi_data, psi_size); + + ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc); + + rc = write(device_fd, &psi_crc, sizeof(psi_crc)); + if (rc < (int) sizeof(psi_crc)) { + ipc_client_log(client, "Writing PSI CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_PSI_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading PSI ACK failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_mipi_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size) +{ + unsigned short boot_magic[4]; + unsigned char ebl_crc; + + int chunk; + int count; + int wc; + + unsigned char *p; + int length; + int rc; + + if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size <= 0) + return -1; + + boot_magic[0] = 0; + boot_magic[1] = 0; + boot_magic[2] = XMM6260_MIPI_BOOT1_MAGIC; + boot_magic[3] = XMM6260_MIPI_BOOT1_MAGIC; + + length = sizeof(boot_magic); + + rc = write(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length)) { + ipc_client_log(client, "Writing boot magic length failed"); + goto error; + } + + rc = write(device_fd, &boot_magic, length); + if (rc < length) { + ipc_client_log(client, "Writing boot magic failed"); + goto error; + } + ipc_client_log(client, "Wrote boot magic"); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_BOOT1_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading boot magic ACK failed"); + goto error; + } + + length = sizeof(ebl_size); + + rc = write(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length)) { + ipc_client_log(client, "Writing EBL size length failed"); + goto error; + } + + rc = write(device_fd, &ebl_size, length); + if (rc < length) { + ipc_client_log(client, "Writing EBL size failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL size"); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_EBL_SIZE_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL size ACK failed"); + goto error; + } + + ebl_size++; + + rc = write(device_fd, &ebl_size, length); + if (rc < length) { + ipc_client_log(client, "Writing EBL size failed"); + goto error; + } + + ebl_size--; + + p = (unsigned char *) ebl_data; + + chunk = XMM6260_MIPI_EBL_CHUNK; + wc = 0; + while (wc < ebl_size) { + count = chunk < ebl_size - wc ? chunk : ebl_size - wc; + + rc = write(device_fd, (void *) p, count); + if (rc < 0) { + ipc_client_log(client, "Writing EBL failed"); + goto error; + } + + p += rc; + wc += rc; + } + + ebl_crc = xmm6260_crc_calculate(ebl_data, ebl_size); + + ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc); + + rc = write(device_fd, &ebl_crc, sizeof(ebl_crc)); + if (rc < (int) sizeof(ebl_crc)) { + ipc_client_log(client, "Writing EBL CRC failed"); + goto error; + } + ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc); + + rc = xmm6260_mipi_ack_read(device_fd, XMM6260_MIPI_EBL_ACK); + if (rc < 0) { + ipc_client_log(client, "Reading EBL ACK failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_mipi_command_send(int device_fd, unsigned short code, + void *data, int size, int ack, int short_tail) +{ + struct xmm6260_mipi_command_header header; + struct xmm6260_mipi_command_tail tail; + int tail_size; + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + int chunk; + int c; + + unsigned char *p; + int rc; + int i; + + if (device_fd < 0 || data == NULL || size <= 0) + return -1; + + header.size = size + sizeof(header); + header.magic = XMM6260_MIPI_COMMAND_HEADER_MAGIC; + header.code = code; + header.data_size = size; + + tail.checksum = (size & 0xffff) + code; + tail.magic = XMM6260_MIPI_COMMAND_TAIL_MAGIC; + tail.unknown = XMM6260_MIPI_COMMAND_TAIL_UNKNOWN; + + p = (unsigned char *) data; + + for (i = 0; i < size; i++) + tail.checksum += *p++; + + tail_size = sizeof(tail); + if (short_tail) + tail_size -= sizeof(short); + + length = sizeof(header) + size + tail_size; + buffer = malloc(length); + + p = (unsigned char *) buffer; + memcpy(p, &header, sizeof(header)); + p += sizeof(header); + memcpy(p, data, size); + p += size; + memcpy(p, &tail, tail_size); + + rc = write(device_fd, buffer, length); + if (rc < length) + goto error; + + free(buffer); + buffer = NULL; + + if (!ack) { + rc = 0; + goto complete; + } + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length) || length <= 0) + goto error; + + length += sizeof(unsigned int); + if (length % 4 != 0) + length += length % 4; + + if (length < (int) sizeof(buffer)) + goto error; + + buffer = malloc(length); + + p = (unsigned char *) buffer; + memcpy(p, &length, sizeof(length)); + p += sizeof(length); + + chunk = 4; + c = sizeof(length); + while (c < length) { + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, (void *) p, chunk); + if (rc < chunk) + goto error; + + p += rc; + c += rc; + } + + memcpy(&header, buffer, sizeof(header)); + if (header.code != code) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_mipi_modem_data_send(int device_fd, void *data, int size, int address) +{ + int chunk; + int count; + int c; + + unsigned char *p; + int rc; + + if (device_fd < 0 || data == NULL || size <= 0) + return -1; + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), 1, 0); + if (rc < 0) + goto error; + + p = (unsigned char *) data; + + chunk = XMM6260_MIPI_MODEM_DATA_CHUNK; + c = 0; + while (c < size) { + count = chunk < size - c ? chunk : size - c; + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_FLASH_WRITE_BLOCK, p, count, 1, 1); + if (rc < 0) + goto error; + + p += count; + c += count; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + return rc; +} + +int xmm6260_mipi_port_config_send(struct ipc_client *client, int device_fd) +{ + void *buffer = NULL; + int length; + + struct timeval timeout; + fd_set fds; + int chunk; + int count; + int c; + + unsigned char *p; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(device_fd, &fds); + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, &length, sizeof(length)); + if (rc < (int) sizeof(length) || length <= 0) { + ipc_client_log(client, "Reading port config length failed"); + goto error; + } + ipc_client_log(client, "Read port config length (0x%x)", length); + + buffer = malloc(length); + + p = (unsigned char *) buffer; + + chunk = 4; + c = 0; + while (c < length) { + count = chunk < length - c ? chunk : length - c; + + rc = select(device_fd + 1, &fds, NULL, NULL, &timeout); + if (rc <= 0) + goto error; + + rc = read(device_fd, p, count); + if (rc < count) { + ipc_client_log(client, "Reading port config failed"); + goto error; + } + + p += count; + c += count; + } + ipc_client_log(client, "Read port config"); + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SET_PORT_CONFIG, buffer, length, 1, 0); + if (rc < 0) { + ipc_client_log(client, "Sending port config command failed"); + goto error; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_mipi_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size <= 0) + return -1; + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SEC_START, sec_data, sec_size, 1, 0); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_sec_end_send(struct ipc_client *client, int device_fd) +{ + unsigned short sec_data; + int sec_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + sec_data = XMM6260_SEC_END_MAGIC; + sec_size = sizeof(sec_data); + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_SEC_END, &sec_data, sec_size, 1, 1); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size <= 0) + return -1; + + rc = xmm6260_mipi_modem_data_send(device_fd, firmware_data, firmware_size, XMM6260_FIRMWARE_ADDRESS); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_nv_data_send(struct ipc_client *client, int device_fd) +{ + void *nv_data = NULL; + int nv_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + rc = nv_data_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data"); + + rc = nv_data_md5_check(client); + if (rc < 0) { + ipc_client_log(client, "Checking nv_data md5 failed"); + goto error; + } + ipc_client_log(client, "Checked nv_data md5"); + + nv_data = file_data_read(nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); + if (nv_data == NULL) { + ipc_client_log(client, "Reading nv_data failed"); + goto error; + } + ipc_client_log(client, "Read nv_data"); + + nv_size = nv_data_size(client); + + rc = xmm6260_mipi_modem_data_send(device_fd, nv_data, nv_size, XMM6260_NV_DATA_ADDRESS); + if (rc < 0) + goto error; + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (nv_data != NULL) + free(nv_data); + + return rc; +} + +int xmm6260_mipi_mps_data_send(struct ipc_client *client, int device_fd, + void *mps_data, int mps_size) +{ + int rc; + + if (client == NULL || device_fd < 0 || mps_data == NULL || mps_size <= 0) + return -1; + + rc = xmm6260_mipi_modem_data_send(device_fd, mps_data, mps_size, XMM6260_MPS_DATA_ADDRESS); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_mipi_hw_reset_send(struct ipc_client *client, int device_fd) +{ + unsigned int hw_reset_data; + int hw_reset_size; + int rc; + + if (client == NULL || device_fd < 0) + return -1; + + hw_reset_data = XMM6260_HW_RESET_MAGIC; + hw_reset_size = sizeof(hw_reset_data); + + rc = xmm6260_mipi_command_send(device_fd, XMM6260_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, 0, 1); + if (rc < 0) + return -1; + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_mipi.h b/samsung-ipc/device/xmm6260/xmm6260_mipi.h new file mode 100644 index 0000000..c8e7c73 --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_mipi.h @@ -0,0 +1,74 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __XMM6260_MIPI_H__ +#define __XMM6260_MIPI_H__ + +#define XMM6260_MIPI_BOOT0_ACK 0xFFFF +#define XMM6260_MIPI_BOOT1_MAGIC 0x02 +#define XMM6260_MIPI_BOOT1_ACK 0xAA00 +#define XMM6260_MIPI_PSI_ACK 0xDD01 +#define XMM6260_MIPI_EBL_SIZE_ACK 0xCCCC +#define XMM6260_MIPI_EBL_ACK 0xA551 +#define XMM6260_MIPI_EBL_CHUNK 0xDFC +#define XMM6260_MIPI_MODEM_DATA_CHUNK 0xDF2 +#define XMM6260_MIPI_COMMAND_HEADER_MAGIC 0x02 +#define XMM6260_MIPI_COMMAND_TAIL_MAGIC 0x03 +#define XMM6260_MIPI_COMMAND_TAIL_UNKNOWN 0xEAEA + +struct xmm6260_mipi_psi_header { + unsigned char padding; + unsigned short length; + unsigned char magic; +} __attribute__((packed)); + +struct xmm6260_mipi_command_header { + unsigned int size; + unsigned short magic; + unsigned short code; + unsigned short data_size; +} __attribute__((packed)); + +struct xmm6260_mipi_command_tail { + unsigned short checksum; + unsigned short magic; + unsigned short unknown; +} __attribute__((packed)); + +int xmm6260_mipi_psi_send(struct ipc_client *client, int device_fd, + void *psi_data, unsigned short psi_size); +int xmm6260_mipi_ebl_send(struct ipc_client *client, int device_fd, + void *ebl_data, int ebl_size); + +int xmm6260_mipi_port_config_send(struct ipc_client *client, int device_fd); +int xmm6260_mipi_sec_start_send(struct ipc_client *client, int device_fd, + void *sec_data, int sec_size); +int xmm6260_mipi_sec_end_send(struct ipc_client *client, int device_fd); +int xmm6260_mipi_firmware_send(struct ipc_client *client, int device_fd, + void *firmware_data, int firmware_size); +int xmm6260_mipi_nv_data_send(struct ipc_client *client, int device_fd); +int xmm6260_mipi_mps_data_send(struct ipc_client *client, int device_fd, + void *mps_data, int mps_size); +int xmm6260_mipi_hw_reset_send(struct ipc_client *client, int device_fd); + +#endif + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_modemctl.c b/samsung-ipc/device/xmm6260/xmm6260_modemctl.c deleted file mode 100644 index e0048e7..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_modemctl.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * XMM6260 Modem Control functions - * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> - * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr> - * - * based on the incomplete C++ implementation which is - * Copyright (C) 2012 Sergey Gridasov <grindars@gmail.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> - -#include <getopt.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/ioctl.h> - -#include <sys/time.h> - -#include <sys/mman.h> -#include <sys/stat.h> - -#include "ipc.h" - -#include "xmm6260_loader.h" -#include "xmm6260_modemctl.h" -#include "modem_prj.h" - -/* - * modemctl generic functions - */ - -int modemctl_link_set_active(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - unsigned status = enabled; - int ret; - unsigned long ioctl_code; - - ioctl_code = IOCTL_LINK_CONTROL_ACTIVE; - ret = ioctl(io_data->link_fd, ioctl_code, &status); - - if (ret < 0) { - ipc_client_log(client, "failed to set link active to %d", enabled); - goto fail; - } - - return 0; - -fail: - return ret; -} - -int modemctl_link_set_enabled(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - unsigned status = enabled; - int ret; - unsigned long ioctl_code; - - ioctl_code = IOCTL_LINK_CONTROL_ENABLE; - ret = ioctl(io_data->link_fd, ioctl_code, &status); - - if (ret < 0) { - ipc_client_log(client, "failed to set link state to %d", enabled); - goto fail; - } - - return 0; -fail: - return ret; -} - -int modemctl_wait_link_ready(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret; - - struct timeval tv_start = {}; - struct timeval tv_end = {}; - - gettimeofday(&tv_start, 0);; - - /* link wakeup timeout in milliseconds */ - long diff = 0; - - do { - ret = ioctl(io_data->link_fd, IOCTL_LINK_CONNECTED, 0); - - if (ret < 0) - goto fail; - - if (ret == 1) - return 0; - - usleep(LINK_POLL_DELAY_US); - gettimeofday(&tv_end, 0);; - - diff = (tv_end.tv_sec - tv_start.tv_sec) * 1000; - diff += (tv_end.tv_usec - tv_start.tv_usec) / 1000; - } while (diff < LINK_TIMEOUT_MS); - - ret = -ETIMEDOUT; - -fail: - return ret; -} - -int modemctl_wait_modem_online(struct ipc_client *client, - struct modemctl_io_data *io_data) -{ - int ret; - - struct timeval tv_start = {}; - struct timeval tv_end = {}; - - gettimeofday(&tv_start, 0);; - - /* link wakeup timeout in milliseconds */ - long diff = 0; - - do { - ret = ioctl(io_data->boot_fd, IOCTL_MODEM_STATUS, 0); - if (ret < 0) - goto fail; - - if (ret == STATE_ONLINE) - return 0; - - usleep(LINK_POLL_DELAY_US); - gettimeofday(&tv_end, 0);; - - diff = (tv_end.tv_sec - tv_start.tv_sec) * 1000; - diff += (tv_end.tv_usec - tv_start.tv_usec) / 1000; - } while (diff < LINK_TIMEOUT_MS); - - ret = -ETIMEDOUT; - -fail: - return ret; -} - -int modemctl_modem_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - if (enabled) - return ioctl(io_data->boot_fd, IOCTL_MODEM_ON, 0); - else - return ioctl(io_data->boot_fd, IOCTL_MODEM_OFF, 0); - - return -1; -} - -int modemctl_modem_boot_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled) -{ - if (enabled) - return ioctl(io_data->boot_fd, IOCTL_MODEM_BOOT_ON, 0); - else - return ioctl(io_data->boot_fd, IOCTL_MODEM_BOOT_OFF, 0); - - return -1; -} - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_modemctl.h b/samsung-ipc/device/xmm6260/xmm6260_modemctl.h deleted file mode 100644 index aab2acb..0000000 --- a/samsung-ipc/device/xmm6260/xmm6260_modemctl.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * XMM6260 Modem Control functions - * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com> - * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr> - * - * based on the incomplete C++ implementation which is - * Copyright (C) 2012 Sergey Gridasov <grindars@gmail.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __XMM6260_MODEMCTL_H__ -#define __XMM6260_MODEMCTL_H__ - -#include <samsung-ipc.h> - -#define MODEM_DEVICE(x) ("/dev/" #x) -#define LINK_PM MODEM_DEVICE(link_pm) -#define MODEM_DEV MODEM_DEVICE(modem_br) -#define BOOT_DEV MODEM_DEVICE(umts_boot0) -#define IPC_DEV MODEM_DEVICE(umts_ipc0) -#define RFS_DEV MODEM_DEVICE(umts_rfs0) - -#define LINK_POLL_DELAY_US (50 * 1000) -#define LINK_TIMEOUT_MS 2000 - -struct modemctl_io_data { - int link_fd; - int boot_fd; - - int radio_fd; - char *radio_data; - struct stat radio_stat; -}; - -/* - * Function prototypes - */ - -/* - * @brief Activates the modem <-> cpu link data transfer - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] whether to enable or disable link data transport - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_link_set_active(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -/* - * @brief Activates the modem <-> cpu link connection - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] the state to set link to - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_link_set_enabled(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -/* - * @brief Poll the link until it gets ready or times out - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_wait_link_ready(struct ipc_client *client, - struct modemctl_io_data *io_data); - -/* - * @brief Poll the modem until it gets online or times out - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_wait_modem_online(struct ipc_client *client, - struct modemctl_io_data *io_data); - -/* - * @brief Sets the modem power - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] whether to enable or disable modem power - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_modem_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -/* - * @brief Sets the modem bootloader power/UART configuration - * - * @param client [in] ipc client - * @param io_data [in] modemctl-specific data - * @param enabled [in] whether to enable or disable power - * @return Negative value indicating error code - * @return ioctl call result - */ -int modemctl_modem_boot_power(struct ipc_client *client, - struct modemctl_io_data *io_data, bool enabled); - -#endif - -// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_sec_modem.c b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.c new file mode 100644 index 0000000..1a3629d --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.c @@ -0,0 +1,500 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/select.h> + +#include <samsung-ipc.h> +#include <ipc.h> +#include <util.h> + +#include "modem.h" +#include "modem_prj.h" +#include "modem_link_device_hsic.h" + +#include "xmm6260.h" +#include "xmm6260_sec_modem.h" + +int xmm6260_sec_modem_power(int device_fd, int power) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, power ? IOCTL_MODEM_ON : IOCTL_MODEM_OFF, 0); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_boot_power(int device_fd, int power) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, power ? IOCTL_MODEM_BOOT_ON : IOCTL_MODEM_BOOT_OFF, 0); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_status_online_wait(int device_fd) +{ + int status; + int i; + + if (device_fd < 0) + return -1; + + i = 0; + for (i = 0; i < 100; i++) { + status = ioctl(device_fd, IOCTL_MODEM_STATUS, 0); + if (status == STATE_ONLINE) + return 0; + + usleep(50000); + } + + return -1; +} + +int xmm6260_sec_modem_hci_power(int power) +{ + int ehci_rc, ohci_rc; + + ehci_rc = sysfs_value_write(XMM6260_SEC_MODEM_EHCI_POWER_SYSFS, !!power); + if (ehci_rc >= 0) + usleep(50000); + + ohci_rc = sysfs_value_write(XMM6260_SEC_MODEM_OHCI_POWER_SYSFS, !!power); + if (ohci_rc >= 0) + usleep(50000); + + if (ehci_rc < 0 && ohci_rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_link_control_enable(int device_fd, int enable) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, IOCTL_LINK_CONTROL_ENABLE, &enable); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_link_control_active(int device_fd, int active) +{ + int rc; + + if (device_fd < 0) + return -1; + + rc = ioctl(device_fd, IOCTL_LINK_CONTROL_ACTIVE, &active); + if (rc < 0) + return -1; + + return 0; +} + +int xmm6260_sec_modem_link_connected_wait(int device_fd) +{ + int status; + int i; + + if (device_fd < 0) + return -1; + + i = 0; + for (i = 0; i < 100; i++) { + status = ioctl(device_fd, IOCTL_LINK_CONNECTED, 0); + if (status) + return 0; + + usleep(50000); + } + + return -1; +} + +int xmm6260_sec_modem_link_get_hostwake_wait(int device_fd) +{ + int status; + int i; + + if (device_fd < 0) + return -1; + + i = 0; + for (i = 0; i < 10; i++) { + status = ioctl(device_fd, IOCTL_LINK_GET_HOSTWAKE, 0); + if (status) + return 0; + + usleep(50000); + } + + return -1; +} + +int xmm6260_sec_modem_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request) +{ + struct ipc_header header; + void *buffer; + unsigned char *p; + int count; + int rc; + + if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL) + return -1; + + ipc_header_fill(&header, request); + + buffer = malloc(header.length); + + memcpy(buffer, &header, sizeof(struct ipc_header)); + if (request->data != NULL && request->length > 0) + memcpy((void *) ((unsigned char *) buffer + sizeof(struct ipc_header)), request->data, request->length); + + ipc_client_log_send(client, request, __func__); + + p = (unsigned char *) buffer; + + count = 0; + while (count < header.length) { + rc = client->handlers->write(client->handlers->transport_data, p, header.length - count); + if (rc <= 0) { + ipc_client_log(client, "Writing FMT data to the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + struct ipc_header *header; + void *buffer = NULL; + unsigned char *p; + int length; + int count; + int rc; + + if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL) + return -1; + + length = XMM6260_DATA_SIZE; + buffer = malloc(length); + + rc = client->handlers->read(client->handlers->transport_data, buffer, length); + if (rc < (int) sizeof(struct ipc_header)) { + ipc_client_log(client, "Reading FMT header from the modem failed"); + goto error; + } + + header = (struct ipc_header *) buffer; + + ipc_message_info_fill(header, response); + + if (header->length > sizeof(struct ipc_header)) { + response->length = header->length - sizeof(struct ipc_header); + response->data = malloc(response->length); + + p = (unsigned char *) response->data; + + count = rc - sizeof(struct ipc_header); + if (count > 0) { + memcpy(p, (void *) ((unsigned char *) buffer + sizeof(struct ipc_header)), count); + p += count; + } + + while (count < (int) response->length) { + rc = client->handlers->read(client->handlers->transport_data, p, response->length - count); + if (rc <= 0) { + ipc_client_log(client, "Reading FMT data from the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + } + + ipc_client_log_recv(client, response, __func__); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request) +{ + struct rfs_hdr header; + void *buffer; + unsigned char *p; + int count; + int rc; + + + if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL) + return -1; + + header.id = request->mseq; + header.cmd = request->index; + header.len = sizeof(struct rfs_hdr) + request->length; + + buffer = malloc(header.len); + + memcpy(buffer, &header, sizeof(struct rfs_hdr)); + if (request->data != NULL && request->length > 0) + memcpy((void *) ((unsigned char *) buffer + sizeof(struct rfs_hdr)), request->data, request->length); + + ipc_client_log_send(client, request, __func__); + + p = (unsigned char *) buffer; + + count = 0; + while (count < (int) header.len) { + rc = client->handlers->write(client->handlers->transport_data, p, header.len - count); + if (rc <= 0) { + ipc_client_log(client, "Writing RFS data to the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response) +{ + struct rfs_hdr *header; + void *buffer = NULL; + unsigned char *p; + int length; + int count; + int rc; + + if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL) + return -1; + + length = XMM6260_DATA_SIZE; + buffer = malloc(length); + + rc = client->handlers->read(client->handlers->transport_data, buffer, length); + if (rc < (int) sizeof(struct rfs_hdr)) { + ipc_client_log(client, "Reading RFS header from the modem failed"); + goto error; + } + + header = (struct rfs_hdr *) buffer; + + memset(response, 0, sizeof(struct ipc_message_info)); + response->aseq = header->id; + response->group = IPC_GROUP_RFS; + response->index = header->cmd; + + if (header->len > sizeof(struct rfs_hdr)) { + response->length = header->len - sizeof(struct rfs_hdr); + response->data = malloc(response->length); + + p = (unsigned char *) response->data; + + count = rc - sizeof(struct rfs_hdr); + if (count > 0) { + memcpy(p, (void *) ((unsigned char *) buffer + sizeof(struct rfs_hdr)), count); + p += count; + } + + while (count < (int) response->length) { + rc = client->handlers->read(client->handlers->transport_data, p, response->length - count); + if (rc <= 0) { + ipc_client_log(client, "Reading RFS data from the modem failed"); + goto error; + } + + count += rc; + p += rc; + } + } + + ipc_client_log_recv(client, response, __func__); + + rc = 0; + goto complete; + +error: + rc = -1; + +complete: + if (buffer != NULL) + free(buffer); + + return rc; +} + +int xmm6260_sec_modem_ipc_open(int type) +{ + int fd; + + switch (type) { + case IPC_CLIENT_TYPE_FMT: + fd = open(XMM6260_SEC_MODEM_IPC0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + break; + case IPC_CLIENT_TYPE_RFS: + fd = open(XMM6260_SEC_MODEM_RFS0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); + break; + default: + return -1; + } + + return fd; +} + +int xmm6260_sec_modem_ipc_close(int fd) +{ + if (fd < 0) + return -1; + + close(fd); + + return 0; +} + +int xmm6260_sec_modem_ipc_read(int fd, void *buffer, unsigned int length) +{ + int rc; + + if (fd < 0 || buffer == NULL || length <= 0) + return -1; + + rc = read(fd, buffer, length); + return rc; +} + +int xmm6260_sec_modem_ipc_write(int fd, void *buffer, unsigned int length) +{ + int rc; + + if (fd < 0 || buffer == NULL || length <= 0) + return -1; + + rc = write(fd, buffer, length); + return rc; +} + +int xmm6260_sec_modem_ipc_poll(int fd, struct timeval *timeout) +{ + fd_set fds; + int rc; + int status; + + if (fd < 0) + return -1; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + rc = select(fd + 1, &fds, NULL, NULL, timeout); + if (FD_ISSET(fd, &fds)) { + status = ioctl(fd, IOCTL_MODEM_STATUS, 0); + if (status != STATE_ONLINE && status != STATE_BOOTING) + return 0; + } + + return rc; +} + +char *xmm6260_sec_modem_ipc_gprs_get_iface(int cid) +{ + char *iface = NULL; + + if (cid > XMM6260_SEC_MODEM_GPRS_IFACE_COUNT) + return NULL; + + asprintf(&iface, "%s%d", XMM6260_SEC_MODEM_GPRS_IFACE_PREFIX, cid - 1); + + return iface; +} + +int xmm6260_sec_modem_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities) +{ + if (capabilities == NULL) + return -1; + + capabilities->port_list = 0; + capabilities->cid_max = XMM6260_SEC_MODEM_GPRS_IFACE_COUNT; + + return 0; +} + +// vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/device/xmm6260/xmm6260_sec_modem.h b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.h new file mode 100644 index 0000000..fc6082b --- /dev/null +++ b/samsung-ipc/device/xmm6260/xmm6260_sec_modem.h @@ -0,0 +1,60 @@ +/* + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2013 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 2 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef __XMM6260_SEC_MODEM_H__ +#define __XMM6260_SEC_MODEM_H__ + +#define XMM6260_SEC_MODEM_BOOT0_DEVICE "/dev/umts_boot0" +#define XMM6260_SEC_MODEM_BOOT1_DEVICE "/dev/umts_boot1" +#define XMM6260_SEC_MODEM_IPC0_DEVICE "/dev/umts_ipc0" +#define XMM6260_SEC_MODEM_RFS0_DEVICE "/dev/umts_rfs0" +#define XMM6260_SEC_MODEM_LINK_PM_DEVICE "/dev/link_pm" +#define XMM6260_SEC_MODEM_EHCI_POWER_SYSFS "/sys/devices/platform/s5p-ehci/ehci_power" +#define XMM6260_SEC_MODEM_OHCI_POWER_SYSFS "/sys/devices/platform/s5p-ehci/ohci_power" + +#define XMM6260_SEC_MODEM_GPRS_IFACE_PREFIX "rmnet" +#define XMM6260_SEC_MODEM_GPRS_IFACE_COUNT 3 + +int xmm6260_sec_modem_power(int device_fd, int power); +int xmm6260_sec_modem_boot_power(int device_fd, int power); +int xmm6260_sec_modem_status_online_wait(int device_fd); +int xmm6260_sec_modem_hci_power(int power); +int xmm6260_sec_modem_link_control_enable(int device_fd, int enable); +int xmm6260_sec_modem_link_control_active(int device_fd, int active); +int xmm6260_sec_modem_link_connected_wait(int device_fd); +int xmm6260_sec_modem_link_get_hostwake_wait(int device_fd); + +int xmm6260_sec_modem_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request); +int xmm6260_sec_modem_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response); +int xmm6260_sec_modem_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request); +int xmm6260_sec_modem_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response); + +int xmm6260_sec_modem_ipc_open(int type); +int xmm6260_sec_modem_ipc_close(int fd); +int xmm6260_sec_modem_ipc_read(int fd, void *buffer, unsigned int length); +int xmm6260_sec_modem_ipc_write(int fd, void *buffer, unsigned int length); +int xmm6260_sec_modem_ipc_poll(int fd, struct timeval *timeout); + +char *xmm6260_sec_modem_ipc_gprs_get_iface(int cid); +int xmm6260_sec_modem_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities); + +#endif + +// vim:ts=4:sw=4:expandtab |