aboutsummaryrefslogtreecommitdiffstats
path: root/samsung-ipc/device/xmm6260
diff options
context:
space:
mode:
Diffstat (limited to 'samsung-ipc/device/xmm6260')
-rw-r--r--samsung-ipc/device/xmm6260/modem.h74
-rwxr-xr-xsamsung-ipc/device/xmm6260/modem_link_device_hsic.h63
-rw-r--r--samsung-ipc/device/xmm6260/modem_prj.h145
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260.c44
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260.h46
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_hsic.c610
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_hsic.h70
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_ipc.c399
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_ipc.h63
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_loader.c104
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_loader.h104
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_mipi.c675
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_mipi.h74
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_modemctl.c181
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_modemctl.h123
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_sec_modem.c500
-rw-r--r--samsung-ipc/device/xmm6260/xmm6260_sec_modem.h60
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