aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/phone_svn
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/phone_svn
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'drivers/phone_svn')
-rw-r--r--drivers/phone_svn/Kconfig71
-rw-r--r--drivers/phone_svn/Makefile4
-rw-r--r--drivers/phone_svn/ipc_spi/Kconfig9
-rw-r--r--drivers/phone_svn/ipc_spi/Makefile2
-rw-r--r--drivers/phone_svn/ipc_spi/ipc_spis.c3923
-rw-r--r--drivers/phone_svn/ipc_spi/spi_app.c183
-rw-r--r--drivers/phone_svn/ipc_spi/spi_app.h15
-rw-r--r--drivers/phone_svn/ipc_spi/spi_data.c981
-rw-r--r--drivers/phone_svn/ipc_spi/spi_data.h129
-rw-r--r--drivers/phone_svn/ipc_spi/spi_dev.c345
-rw-r--r--drivers/phone_svn/ipc_spi/spi_dev.h49
-rw-r--r--drivers/phone_svn/ipc_spi/spi_main.c563
-rw-r--r--drivers/phone_svn/ipc_spi/spi_main.h80
-rw-r--r--drivers/phone_svn/ipc_spi/spi_os.c634
-rw-r--r--drivers/phone_svn/ipc_spi/spi_os.h82
-rw-r--r--drivers/phone_svn/ipc_spi/spi_test.c270
-rw-r--r--drivers/phone_svn/ipc_spi/spi_test.h14
-rw-r--r--drivers/phone_svn/svnet/Makefile5
-rw-r--r--drivers/phone_svn/svnet/main.c867
-rw-r--r--drivers/phone_svn/svnet/main.h5
-rw-r--r--drivers/phone_svn/svnet/pdp.c100
-rw-r--r--drivers/phone_svn/svnet/pdp.h35
-rw-r--r--drivers/phone_svn/svnet/sipc.h64
-rw-r--r--drivers/phone_svn/svnet/sipc4.c2119
-rw-r--r--drivers/phone_svn/svnet/sipc4.h267
25 files changed, 10816 insertions, 0 deletions
diff --git a/drivers/phone_svn/Kconfig b/drivers/phone_svn/Kconfig
new file mode 100644
index 0000000..9146f77
--- /dev/null
+++ b/drivers/phone_svn/Kconfig
@@ -0,0 +1,71 @@
+#
+#
+#
+
+menuconfig SAMSUNG_PHONE_SVNET
+ tristate "Samsung Phone Interface - SVN"
+ default n
+ ---help---
+
+if SAMSUNG_PHONE_SVNET
+
+menuconfig PHONE_ONEDRAM
+ tristate "OneDRAM"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+ help
+ Say Y to enable OneDRAM Interface support.
+
+config PHONE_IPC_SPI
+ bool "IPC SPI"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+ help
+ Say Y to enable IPC-SPI Interface support.
+
+menuconfig PHONE_IPC_HSI
+ tristate "IPC HSI"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+ help
+ Say Y to enable MIPI-HSI Interface support.
+
+config PHONE_SVNET
+ tristate "Samsung Virtual Network"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+ help
+ Say Y to enable Samsung Virtual Network support
+
+menuconfig PHONE_LOOPBACK_TEST
+ tristate "SPI LoopBack Test"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+
+menuconfig PHONE_STORAGE
+ tristate "DGS Storage"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+
+config SVNET_WHITELIST
+ bool "svnet uses whitelist via onedram"
+ default n
+ ---help---
+ By default, n
+
+config CHN_CMCC_SPI_SPRD
+ tristate "Samsung M0-TD CP SPRD"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+
+config SEC_MODEM_M0_TD
+ tristate "Samsung M0-TD modemctl driver"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+
+config WORKQUEUE_FRONT
+ tristate "IPC_SPI workqueue front"
+ depends on SAMSUNG_PHONE_SVNET
+ default n
+
+endif # SAMSUNG_PHONE_SVNET
diff --git a/drivers/phone_svn/Makefile b/drivers/phone_svn/Makefile
new file mode 100644
index 0000000..38664e0
--- /dev/null
+++ b/drivers/phone_svn/Makefile
@@ -0,0 +1,4 @@
+# IPC_SPI kernel driver
+
+obj-$(CONFIG_PHONE_IPC_SPI) += ipc_spi/
+obj-$(CONFIG_PHONE_SVNET) += svnet/
diff --git a/drivers/phone_svn/ipc_spi/Kconfig b/drivers/phone_svn/ipc_spi/Kconfig
new file mode 100644
index 0000000..fb1386c
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/Kconfig
@@ -0,0 +1,9 @@
+#
+# OneDRAM configuration
+#
+config DPRAM_BUILT_IN
+ tristate "onedram driver built-in"
+
+config SVNET_WHITELIST
+ bool "svnet uses whitelist via onedram"
+ default n
diff --git a/drivers/phone_svn/ipc_spi/Makefile b/drivers/phone_svn/ipc_spi/Makefile
new file mode 100644
index 0000000..28a66e6
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/Makefile
@@ -0,0 +1,2 @@
+ipc_spi-objs := ipc_spis.o spi_app.o spi_data.o spi_dev.o spi_main.o spi_os.o
+obj-$(CONFIG_PHONE_IPC_SPI) += ipc_spi.o
diff --git a/drivers/phone_svn/ipc_spi/ipc_spis.c b/drivers/phone_svn/ipc_spi/ipc_spis.c
new file mode 100644
index 0000000..331a238
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/ipc_spis.c
@@ -0,0 +1,3923 @@
+#define FEATURE_SAMSUNG_SPI
+
+/**
+ * Samsung Virtual Network driver using IpcSpi device
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#define DEBUG
+
+/*
+#define FORMAT_TX_DUMP
+#define RAW_TX_DUMP
+#define RFS_TX_DUMP
+#define FORMAT_RX_DUMP
+#define RAW_RX_DUMP
+#define RFS_RX_DUMP
+#define RAW_TX_RX_LENGTH_DUMP
+#define RFS_TX_RX_LENGTH_DUMP
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/phone_svn/ipc_spi.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include <linux/vmalloc.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/in.h>
+#include <mach/regs-pmu.h>
+#include <linux/kthread.h>
+#include <linux/err.h>
+
+#include <linux/workqueue.h>
+#ifdef FEATURE_SAMSUNG_SPI
+#include "spi_main.h"
+#endif
+
+#define DRVNAME "onedram"
+
+#define ONEDRAM_REG_OFFSET 0xFFF800
+#define ONEDRAM_REG_SIZE 0x800
+
+#define MB_VALID 0x0080
+#define MB_COMMAND 0x0040
+
+#define MB_CMD(x) (MB_VALID | MB_COMMAND | x)
+#define MB_DATA(x) (MB_VALID | x)
+
+#define MBD_SEND_FMT 0x0002
+#define MBD_SEND_RAW 0x0001
+#define MBD_SEND_RFS 0x0100
+#define MBD_REQ_ACK_FMT 0x0020
+#define MBD_REQ_ACK_RAW 0x0010
+#define MBD_REQ_ACK_RFS 0x0400
+#define MBD_RES_ACK_FMT 0x0008
+#define MBD_RES_ACK_RAW 0x0004
+#define MBD_RES_ACK_RFS 0x0200
+
+
+#define FMT_OUT 0x0FE000
+#define FMT_IN 0x10E000
+#define FMT_SZ 0x10000 /* 65536 bytes */
+
+#define RAW_OUT 0x11E000
+#define RAW_IN 0x21E000
+#define RAW_SZ 0x100000 /* 1 MB */
+
+#define RFS_OUT 0x31E000
+#define RFS_IN 0x41E000
+#define RFS_SZ 0x100000 /* 1 MB */
+
+static u32 ipc_spi_get_send_vbuff_command(void);
+static void ipc_spi_set_send_vbuff_command_clear(void);
+static inline void ipc_spi_get_pointer_of_vbuff_format_tx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_format_rx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_raw_tx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_raw_rx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_tx(u32 *head, u32 *tail);
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_rx(u32 *head, u32 *tail);
+static inline void ipc_spi_update_tail_of_vbuff_format_tx(u32 u_tail);
+static inline void ipc_spi_update_head_of_vbuff_format_rx(u32 u_head);
+static inline void ipc_spi_update_tail_of_vbuff_raw_tx(u32 u_tail);
+static inline void ipc_spi_update_head_of_vbuff_raw_rx(u32 u_head);
+static inline void ipc_spi_update_tail_of_vbuff_rfs_tx(u32 u_tail);
+static inline void ipc_spi_update_head_of_vbuff_rfs_rx(u32 u_head);
+/*
+#define LOOPBACK_TEST
+*/
+#ifdef LOOPBACK_TEST
+int loop_back_test = 1;
+#define LOOP_SIZE 2048
+#else
+int loop_back_test;
+#endif
+
+enum {
+ MBC_NONE = 0,
+ MBC_INIT_START,
+ MBC_INIT_END,
+ MBC_REQ_ACTIVE,
+ MBC_RES_ACTIVE,
+ MBC_TIME_SYNC,
+ MBC_POWER_OFF,
+ MBC_RESET,
+ MBC_PHONE_START,
+ MBC_ERR_DISPLAY,
+ MBC_POWER_SAVE,
+ MBC_NV_REBUILD,
+ MBC_EMER_DOWN,
+ MBC_REQ_SEM,
+ MBC_RES_SEM,
+ MBC_MAX
+};
+#define MBC_MASK 0xFF
+
+#define MAX_BUF_SIZE 2044
+#define DEF_BUF_SIZE MAX_BUF_SIZE
+
+static struct spi_device *p_ipc_spi;
+
+#ifdef LOOPBACK_TEST
+struct spi_protocol_header {
+ unsigned long current_data_size:12;
+ unsigned long more:1;
+ unsigned long rx_error:1;
+ unsigned long packet_id:2;
+ unsigned long reserved:2;
+ unsigned long next_data_size:10;
+ unsigned long RI:1;
+ unsigned long DCD:1;
+ unsigned long RTSCTS:1;
+ unsigned long DSRDTR:1;
+};
+#else
+struct spi_protocol_header {
+ unsigned long current_data_size:31;
+ unsigned long more:1;
+};
+#endif
+
+struct onedram_reg_mapped {
+ u32 sem;
+ u32 reserved1[7];
+ u32 mailbox_AB; /* CP write, AP read */
+ u32 reserved2[7];
+ u32 mailbox_BA; /*AP write, CP read */
+ u32 reserved3[23];
+ u32 check_AB; /* can't read */
+ u32 reserved4[7];
+ u32 check_BA; /* 0: CP read, 1: CP don't read */
+};
+
+struct ipc_spi_handler {
+ struct list_head list;
+ void *data;
+ void (*handler)(u32, void *);
+};
+
+struct ipc_spi_handler_head {
+ struct list_head list;
+ u32 len;
+ spinlock_t lock;
+};
+static struct ipc_spi_handler_head h_list;
+
+static struct resource ipc_spi_resource = {
+ .name = DRVNAME,
+ .start = 0,
+ .end = -1,
+ .flags = IORESOURCE_MEM,
+};
+
+struct ipc_spi {
+ struct class *class;
+ struct device *dev;
+ struct cdev cdev;
+ dev_t devid;
+
+ wait_queue_head_t waitq;
+ struct fasync_struct *async_queue;
+ u32 mailbox;
+
+ unsigned long base;
+ unsigned long size;
+ void __iomem *mmio;
+
+ int irq;
+
+ struct completion comp;
+ atomic_t ref_sem;
+ unsigned long flags;
+
+ const struct attribute_group *group;
+
+ struct onedram_reg_mapped *reg;
+};
+struct ipc_spi *ipc_spi;
+
+struct workqueue_struct *ipc_spi_wq;
+struct ipc_spi_send_modem_bin_workq_data {
+ struct ipc_spi *od;
+
+ struct work_struct send_modem_w;
+};
+struct ipc_spi_send_modem_bin_workq_data *ipc_spi_send_modem_work_data;
+
+static DEFINE_SPINLOCK(ipc_spi_lock);
+
+static unsigned long hw_tmp; /* for hardware */
+static inline int _read_sem(struct ipc_spi *od);
+static inline void _write_sem(struct ipc_spi *od, int v);
+static int ipc_spi_thread_restart(void);
+static inline void ipc_spi_get_pointer_of_vbuff_format_tx(u32 *head, u32 *tail);
+
+struct completion ril_init;
+static unsigned gpio_mrdy;
+static unsigned gpio_srdy;
+struct semaphore srdy_sem;
+struct semaphore transfer_event_sem;
+int send_modem_spi = 1;
+int is_cp_reset;
+int boot_done;
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+int transfer_thread_waiting;
+
+static void __iomem *p_virtual_buff;
+
+static unsigned long recv_cnt;
+static unsigned long send_cnt;
+static ssize_t show_debug(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ char *p = buf;
+ struct ipc_spi *od = dev_get_drvdata(d);
+
+ if (!od)
+ return 0;
+
+ p += sprintf(p, "Semaphore: %d (%d)\n", _read_sem(od), (char)hw_tmp);
+ p += sprintf(p, "Mailbox: %x\n", od->reg->mailbox_AB);
+ p += sprintf(p, "Reference count: %d\n", atomic_read(&od->ref_sem));
+ p += sprintf(p, "Mailbox send: %lu\n", send_cnt);
+ p += sprintf(p, "Mailbox recv: %lu\n", recv_cnt);
+
+ return p - buf;
+}
+
+
+#ifdef FEATURE_SAMSUNG_SPI
+void *ipc_spi_get_queue_buff(void)
+{
+ return (void *)p_virtual_buff;
+}
+#endif
+
+
+static DEVICE_ATTR(debug, S_IRUGO, show_debug, NULL);
+
+static struct attribute *ipc_spi_attributes[] = {
+ &dev_attr_debug.attr,
+ NULL
+};
+
+static const struct attribute_group ipc_spi_group = {
+ .attrs = ipc_spi_attributes,
+};
+
+static inline void _write_sem(struct ipc_spi *od, int v)
+{
+ od->reg->sem = 1;
+
+ hw_tmp = od->reg->sem; /* for hardware */
+}
+
+static inline int _read_sem(struct ipc_spi *od)
+{
+ od->reg->sem = 1;
+
+ return od->reg->sem;
+}
+
+static inline int _send_cmd(struct ipc_spi *od, u32 cmd)
+{
+ u32 tmp_cmd;
+
+ if (!od) {
+ printk(KERN_ERR "[%s]ipcspi: Dev is NULL, but try to access\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to send cmd, not initialized\n",
+ __LINE__);
+
+ return -EFAULT;
+ }
+
+ if (cmd & MB_VALID) {
+ if (cmd & MB_COMMAND) {
+ tmp_cmd = (cmd & MBC_MASK) & ~(MB_CMD(0));
+
+ switch (tmp_cmd) {
+ case MBC_INIT_END: /* 0x0002 */
+ dev_info(od->dev, "(%d) send ril init cmd : %x\n",
+ __LINE__, cmd);
+
+ send_cnt++;
+ od->reg->mailbox_BA = cmd;
+
+#ifdef FEATURE_SAMSUNG_SPI
+ spi_main_send_signal(SPI_MAIN_MSG_IPC_SEND);
+#else
+ if (transfer_thread_waiting) {
+ transfer_thread_waiting = 0;
+ up(&transfer_event_sem);
+ }
+#endif
+
+ complete_all(&ril_init);
+
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ dev_dbg(od->dev, "(%d) =>send data (0x%x)\n",
+ __LINE__, cmd);
+
+#ifdef FEATURE_SAMSUNG_SPI
+ spi_main_send_signal(SPI_MAIN_MSG_IPC_SEND);
+#else
+ if (transfer_thread_waiting) {
+ transfer_thread_waiting = 0;
+ up(&transfer_event_sem);
+ }
+#endif
+ }
+ } else {
+ if (cmd == 0x45674567) {
+ dev_dbg(od->dev, "(%d) modem image loaded.\n",
+ __LINE__);
+ dev_dbg(od->dev, "(%d) start to send modem binary to cp.\n",
+ __LINE__);
+
+ ipc_spi_send_modem_work_data->od = od;
+ if (!queue_work(ipc_spi_wq,
+ &ipc_spi_send_modem_work_data->send_modem_w))
+ dev_err(od->dev, "(%d) already exist w-q\n", __LINE__);
+
+ } else {
+ dev_err(od->dev, "(%d) send invalid cmd : 0x%x\n",
+ __LINE__, cmd);
+ }
+ }
+
+ return 0;
+}
+
+static inline int _recv_cmd(struct ipc_spi *od, u32 *cmd)
+{
+ if (!cmd)
+ return -EINVAL;
+
+ if (!od) {
+ printk(KERN_ERR "[%s]ipcspi: Dev is NULL, but try to access\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to read cmd, not initialized\n",
+ __LINE__);
+
+ return -EFAULT;
+ }
+
+ recv_cnt++;
+ *cmd = od->reg->mailbox_AB;
+ return 0;
+}
+
+static inline int _get_auth(struct ipc_spi *od, u32 cmd)
+{
+ unsigned long timeleft;
+ int retry = 0;
+
+ /* send cmd every 20m seconds */
+ while (1) {
+ _send_cmd(od, cmd);
+
+ timeleft = wait_for_completion_timeout(&od->comp, HZ/50);
+#if 0
+ if (timeleft)
+ break;
+#endif
+ if (_read_sem(od))
+ break;
+
+ retry++;
+ if (retry > 50) { /* time out after 1 seconds */
+ dev_err(od->dev, "(%d) get authority time out\n", __LINE__);
+
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int get_auth(struct ipc_spi *od, u32 cmd)
+{
+ int r;
+
+ if (!od) {
+ printk(KERN_ERR "[%s]ipcspi: Dev is NULL, but try to access\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to get authority\n", __LINE__);
+
+ return -EFAULT;
+ }
+
+ if (_read_sem(od))
+ return 0;
+
+ if (cmd)
+ r = _get_auth(od, cmd);
+ else
+ r = -EACCES;
+
+ return r;
+}
+
+static int put_auth(struct ipc_spi *od, int release)
+{
+ if (!od) {
+ printk(KERN_ERR "[%s]onedram: Dev is NULL, but try to access\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to put authority\n", __LINE__);
+
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int rel_sem(struct ipc_spi *od)
+{
+ if (!od) {
+ printk(KERN_ERR "[%s]onedram: Dev is NULL, but try to access\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!od->reg) {
+ dev_err(od->dev, "(%d) Failed to put authority\n", __LINE__);
+
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int onedram_read_mailbox(u32 *mb)
+{
+ return _recv_cmd(ipc_spi, mb);
+}
+EXPORT_SYMBOL(onedram_read_mailbox);
+
+int onedram_write_mailbox(u32 mb)
+{
+ return _send_cmd(ipc_spi, mb);
+}
+EXPORT_SYMBOL(onedram_write_mailbox);
+
+void onedram_init_mailbox(void)
+{
+ int r = 0;
+ /* flush mailbox before registering onedram irq */
+ r = ipc_spi->reg->mailbox_AB;
+
+ /* Set nINT_ONEDRAM_CP to low */
+ ipc_spi->reg->mailbox_BA = 0x0;
+}
+EXPORT_SYMBOL(onedram_init_mailbox);
+
+int onedram_get_auth(u32 cmd)
+{
+ return get_auth(ipc_spi, cmd);
+}
+EXPORT_SYMBOL(onedram_get_auth);
+
+int onedram_put_auth(int release)
+{
+ return put_auth(ipc_spi, release);
+}
+EXPORT_SYMBOL(onedram_put_auth);
+
+int onedram_rel_sem(void)
+{
+ return rel_sem(ipc_spi);
+}
+EXPORT_SYMBOL(onedram_rel_sem);
+
+int onedram_read_sem(void)
+{
+ return _read_sem(ipc_spi);
+}
+EXPORT_SYMBOL(onedram_read_sem);
+
+void onedram_get_vbase(void **vbase)
+{
+ *vbase = (void *)ipc_spi->mmio;
+}
+EXPORT_SYMBOL(onedram_get_vbase);
+
+
+static int ipc_spi_irq_log_flag;
+static irqreturn_t ipc_spi_irq_handler(int irq, void *data) /* SRDY Rising EDGE ISR */
+{
+ struct ipc_spi *od = (struct ipc_spi *)data;
+ int srdy_pin = 0;
+
+ srdy_pin = gpio_get_value(gpio_srdy);
+
+ if (!boot_done)
+ return IRQ_HANDLED;
+
+ /*
+ if (ipc_spi_irq_log_flag)
+ dev_dbg(od->dev, "(%d) isr SRDY : %d\n", __LINE__, srdy_pin);
+ */
+
+ if (!srdy_pin) {
+ printk(KERN_ERR "SRDY LOW.\n");
+ return IRQ_HANDLED;
+ }
+
+ up(&srdy_sem);
+
+ if (transfer_thread_waiting) {
+ transfer_thread_waiting = 0;
+
+ if (ipc_spi_irq_log_flag)
+ dev_dbg(od->dev, "(%d) signal transfer event.\n", __LINE__);
+
+ up(&transfer_event_sem);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ipc_spi_vm_pagefault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct ipc_spi *od = vma->vm_private_data;
+
+ vmf->page = vmalloc_to_page(od->mmio + (vmf->pgoff << PAGE_SHIFT));
+ get_page(vmf->page);
+
+ return 0;
+}
+
+static struct vm_operations_struct ipc_spi_vm_ops = {
+ .fault = ipc_spi_vm_pagefault,
+};
+
+static int ipc_spi_open(struct inode *inode, struct file *filp)
+{
+ struct cdev *cdev = inode->i_cdev;
+ struct ipc_spi *od = container_of(cdev, struct ipc_spi, cdev);
+
+ filp->private_data = od;
+ return 0;
+}
+
+static int ipc_spi_release(struct inode *inode, struct file *filp)
+{
+ filp->private_data = NULL;
+ return 0;
+}
+
+static unsigned int ipc_spi_poll(struct file *filp, poll_table *wait)
+{
+ struct ipc_spi *od;
+ u32 data;
+
+ od = filp->private_data;
+
+ poll_wait(filp, &od->waitq, wait);
+
+ spin_lock_irq(&ipc_spi_lock);
+ data = od->mailbox;
+ spin_unlock_irq(&ipc_spi_lock);
+
+ if (data)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static ssize_t ipc_spi_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ u32 data;
+ ssize_t retval;
+ struct ipc_spi *od;
+
+ od = filp->private_data;
+
+ if (count < sizeof(u32))
+ return -EINVAL;
+
+ add_wait_queue(&od->waitq, &wait);
+
+ while (1) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_irq(&ipc_spi_lock);
+ data = od->mailbox;
+ od->mailbox = 0;
+ spin_unlock_irq(&ipc_spi_lock);
+
+ if (data)
+ break;
+ else if (filp->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto out;
+ } else if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ goto out;
+ }
+ schedule();
+ }
+
+ retval = put_user(data, (u32 __user *)buf);
+ if (!retval)
+ retval = sizeof(u32);
+out:
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&od->waitq, &wait);
+
+ return retval;
+}
+
+static ssize_t ipc_spi_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct ipc_spi *od;
+
+ od = filp->private_data;
+
+ if (count) {
+ u32 data;
+
+ if (get_user(data, (u32 __user *)buf))
+ return -EFAULT;
+
+ _send_cmd(od, data);
+ }
+
+ return count;
+}
+
+static int ipc_spi_fasync(int fd, struct file *filp, int on)
+{
+ struct ipc_spi *od;
+
+ od = filp->private_data;
+
+ return fasync_helper(fd, filp, on, &od->async_queue);
+}
+
+static int ipc_spi_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct ipc_spi *od;
+ unsigned long size;
+ unsigned long offset;
+
+ od = filp->private_data;
+ if (!od || !vma)
+ return -EFAULT;
+
+ size = vma->vm_end - vma->vm_start;
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ dev_dbg(od->dev, "(%d) Req region: 0x%08lx 0x%08lx\n", __LINE__, offset, size);
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ipc_spi_vm_ops;
+ vma->vm_private_data = od;
+
+ dev_dbg(od->dev, "(%d) ipc_spi_mmap Done.\n", __LINE__);
+
+ return 0;
+}
+
+int ipc_spi_sema_init(void)
+{
+ printk(KERN_ERR "[SPI] Srdy sema init\n");
+ sema_init(&srdy_sem, 0);
+ return 0;
+}
+
+static long ipc_spi_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+
+ int r = 0;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ switch (cmd) {
+ case ONEDRAM_CP_CRASH:
+ panic("CP Crash");
+ break;
+ case ONEDRAM_REL_SEM:
+ r = ipc_spi_thread_restart();
+ break;
+ case ONEDRAM_SEMA_INIT:
+ r = ipc_spi_sema_init();
+ break;
+ default:
+ r = -ENOIOCTLCMD;
+ break;
+ }
+
+ return r;
+}
+
+static const struct file_operations ipc_spi_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .read = ipc_spi_read,
+ .write = ipc_spi_write,
+ .poll = ipc_spi_poll,
+ .fasync = ipc_spi_fasync,
+ .open = ipc_spi_open,
+ .release = ipc_spi_release,
+ .mmap = ipc_spi_mmap,
+ .unlocked_ioctl = ipc_spi_ioctl,
+};
+
+static int _register_chrdev(struct ipc_spi *od)
+{
+ int r;
+ dev_t devid;
+
+ od->class = class_create(THIS_MODULE, DRVNAME);
+ if (IS_ERR(od->class)) {
+ r = PTR_ERR(od->class);
+ od->class = NULL;
+ return r;
+ }
+
+ r = alloc_chrdev_region(&devid, 0, 1, DRVNAME);
+ if (r)
+ return r;
+
+ cdev_init(&od->cdev, &ipc_spi_fops);
+
+ r = cdev_add(&od->cdev, devid, 1);
+ if (r) {
+ unregister_chrdev_region(devid, 1);
+ return r;
+ }
+ od->devid = devid;
+
+ od->dev = device_create(od->class, NULL, od->devid, od, DRVNAME);
+ if (IS_ERR(od->dev)) {
+ r = PTR_ERR(od->dev);
+ od->dev = NULL;
+ return r;
+ }
+ dev_set_drvdata(od->dev, od);
+
+ return 0;
+}
+
+static inline int _request_mem(struct ipc_spi *od, struct platform_device *pdev)
+{
+ od->mmio = vmalloc(od->size);
+ if (!od->mmio) {
+ dev_err(&pdev->dev, "(%d) Failed to vmalloc size : %lu\n", __LINE__, od->size);
+
+ return -EBUSY;
+ } else {
+ dev_dbg(&pdev->dev, "(%d) vmalloc Done. mmio : 0x%08x\n", __LINE__, (u32)od->mmio);
+ }
+
+ memset((void *)od->mmio, 0, od->size);
+
+ od->reg = (struct onedram_reg_mapped *)(
+ (char *)od->mmio + ONEDRAM_REG_OFFSET);
+ dev_dbg(&pdev->dev, "(%d) Onedram semaphore: %d\n", __LINE__, _read_sem(od));
+
+ od->reg->sem = 1;
+ dev_dbg(&pdev->dev, "(%d) force set sem to 1 : %d\n", __LINE__, od->reg->sem);
+
+ od->reg->mailbox_AB = 0x000000C8;
+ od->reg->mailbox_BA = 0;
+ dev_dbg(&pdev->dev, "(%d) force set mailbox to 0 : AB=0x%x, BA=0x%x\n", __LINE__, od->reg->mailbox_AB, od->reg->mailbox_BA);
+
+ ipc_spi_resource.start = (resource_size_t)od->mmio;
+ ipc_spi_resource.end = (resource_size_t)od->mmio + od->size - 1;
+
+ p_virtual_buff = od->mmio;
+
+ return 0;
+}
+
+static void _release(struct ipc_spi *od)
+{
+ if (!od)
+ return;
+
+ if (od->irq)
+ free_irq(od->irq, od);
+
+ if (od->group)
+ sysfs_remove_group(&od->dev->kobj, od->group);
+
+ if (od->dev)
+ device_destroy(od->class, od->devid);
+
+ if (od->devid) {
+ cdev_del(&od->cdev);
+ unregister_chrdev_region(od->devid, 1);
+ }
+
+ if (od->mmio) {
+ od->reg = NULL;
+
+ vfree((void *)od->mmio);
+
+ ipc_spi_resource.start = 0;
+ ipc_spi_resource.end = -1;
+ }
+
+ if (od->class)
+ class_destroy(od->class);
+
+ kfree(od);
+}
+
+struct resource *onedram_request_region(resource_size_t start,
+ resource_size_t n, const char *name)
+{
+ struct resource *res;
+
+ start += ipc_spi_resource.start;
+ res = __request_region(&ipc_spi_resource, start, n, name, 0);
+ if (!res)
+ return NULL;
+
+ return res;
+}
+EXPORT_SYMBOL(onedram_request_region);
+
+void onedram_release_region(resource_size_t start, resource_size_t n)
+{
+ start += ipc_spi_resource.start;
+ __release_region(&ipc_spi_resource, start, n);
+}
+EXPORT_SYMBOL(onedram_release_region);
+
+int onedram_register_handler(void (*handler)(u32, void *), void *data)
+{
+ unsigned long flags;
+ struct ipc_spi_handler *hd;
+
+ if (!handler)
+ return -EINVAL;
+
+ hd = kzalloc(sizeof(struct ipc_spi_handler), GFP_KERNEL);
+ if (!hd)
+ return -ENOMEM;
+
+ hd->data = data;
+ hd->handler = handler;
+
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_add_tail(&hd->list, &h_list.list);
+ h_list.len++;
+ spin_unlock_irqrestore(&h_list.lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(onedram_register_handler);
+
+int onedram_unregister_handler(void (*handler)(u32, void *))
+{
+ unsigned long flags;
+ struct list_head *l, *tmp;
+
+ if (!handler)
+ return -EINVAL;
+
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_for_each_safe(l, tmp, &h_list.list) {
+ struct ipc_spi_handler *hd = list_entry(l, struct ipc_spi_handler, list);
+
+ if (hd->handler == handler) {
+ list_del(&hd->list);
+ h_list.len--;
+ kfree(hd);
+ }
+ }
+ spin_unlock_irqrestore(&h_list.lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(onedram_unregister_handler);
+
+static void _unregister_all_handlers(void)
+{
+ unsigned long flags;
+ struct list_head *l, *tmp;
+
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_for_each_safe(l, tmp, &h_list.list) {
+ struct ipc_spi_handler *hd = list_entry(l, struct ipc_spi_handler, list);
+
+ list_del(&hd->list);
+ h_list.len--;
+ kfree(hd);
+ }
+ spin_unlock_irqrestore(&h_list.lock, flags);
+}
+
+static void _init_data(struct ipc_spi *od)
+{
+ init_completion(&od->comp);
+ atomic_set(&od->ref_sem, 0);
+ INIT_LIST_HEAD(&h_list.list);
+ spin_lock_init(&h_list.lock);
+ h_list.len = 0;
+ init_waitqueue_head(&od->waitq);
+
+ init_completion(&ril_init);
+ sema_init(&srdy_sem, 0);
+ sema_init(&transfer_event_sem, 0);
+}
+
+static u32 ipc_spi_get_send_vbuff_command(void)
+{
+ u32 cmd = 0;
+
+ memcpy((void *)&cmd, (void *)(p_virtual_buff + ONEDRAM_REG_OFFSET + 64), sizeof(cmd));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get mailbox_BA cmd : 0x%x\n", __LINE__, cmd); */
+
+ return cmd;
+}
+
+static void ipc_spi_set_send_vbuff_command_clear(void)
+{
+ u32 cmd = 0;
+
+ memcpy((void *)(p_virtual_buff + ONEDRAM_REG_OFFSET + 64), (void *)&cmd, sizeof(cmd));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) clear mailbox_BA cmd : 0x%x\n", __LINE__, cmd); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_format_tx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 16), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 20), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT tx_head : %d, tx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_format_rx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 16 + 8), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 20 + 8), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT rx_head : %d, rx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_raw_tx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 32), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 36), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW tx_head : %d, tx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_raw_rx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 32 + 8), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 36 + 8), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW rx_head : %d, rx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_tx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 48), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 52), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS tx_head : %d, tx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_get_pointer_of_vbuff_rfs_rx(u32 *head, u32 *tail)
+{
+ memcpy((void *)head, (void *)(p_virtual_buff + 48 + 8), sizeof(*head));
+ memcpy((void *)tail, (void *)(p_virtual_buff + 52 + 8), sizeof(*tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS rx_head : %d, rx_tail : %d\n", __LINE__, *head, *tail); */
+}
+
+static inline void ipc_spi_update_tail_of_vbuff_format_tx(u32 u_tail)
+{
+ memcpy((void *)(p_virtual_buff + 20), (void *)&u_tail, sizeof(u_tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update FMT tx_tail : %d\n", __LINE__, u_tail); */
+}
+
+static inline void ipc_spi_update_head_of_vbuff_format_rx(u32 u_head)
+{
+ memcpy((void *)(p_virtual_buff + 20 + 4), (void *)&u_head, sizeof(u_head));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update FMT rx_head : %d\n", __LINE__, u_head); */
+}
+
+static inline void ipc_spi_update_tail_of_vbuff_raw_tx(u32 u_tail)
+{
+ memcpy((void *)(p_virtual_buff + 36), (void *)&u_tail, sizeof(u_tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RAW tx_tail : %d\n", __LINE__, u_tail); */
+}
+
+static inline void ipc_spi_update_head_of_vbuff_raw_rx(u32 u_head)
+{
+ memcpy((void *)(p_virtual_buff + 36 + 4), (void *)&u_head, sizeof(u_head));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RAW rx_head : %d\n", __LINE__, u_head); */
+}
+
+static inline void ipc_spi_update_tail_of_vbuff_rfs_tx(u32 u_tail)
+{
+ memcpy((void *)(p_virtual_buff + 52), (void *)&u_tail, sizeof(u_tail));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RFS tx_tail : %d\n", __LINE__, u_tail); */
+}
+
+static inline void ipc_spi_update_head_of_vbuff_rfs_rx(u32 u_head)
+{
+ memcpy((void *)(p_virtual_buff + 52 + 4), (void *)&u_head, sizeof(u_head));
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) update RFS rx_head : %d\n", __LINE__, u_head); */
+}
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+u32 ipc_spi_get_length_vbuff_format_tx(u32 *out_head, u32 *out_tail)
+{
+ u32 len = 0;
+
+ ipc_spi_get_pointer_of_vbuff_format_tx(out_head, out_tail);
+
+ if (*out_head >= *out_tail)
+ len = *out_head - *out_tail;
+ else
+ len = FMT_SZ - *out_tail + *out_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT tx_len : %d\n", __LINE__, len); */
+
+ return len;
+}
+
+static u32 ipc_spi_get_length_vbuff_raw_tx(u32 *out_head, u32 *out_tail)
+{
+ u32 len = 0;
+
+ ipc_spi_get_pointer_of_vbuff_raw_tx(out_head, out_tail);
+
+ if (*out_head >= *out_tail)
+ len = *out_head - *out_tail;
+ else
+ len = RAW_SZ - *out_tail + *out_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW tx_len : %d\n", __LINE__, len); */
+
+ return len;
+}
+
+static u32 ipc_spi_get_length_vbuff_rfs_tx(u32 *out_head, u32 *out_tail)
+{
+ u32 len = 0;
+
+ ipc_spi_get_pointer_of_vbuff_rfs_tx(out_head, out_tail);
+
+ if (*out_head >= *out_tail)
+ len = *out_head - *out_tail;
+ else
+ len = RFS_SZ - *out_tail + *out_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS tx_len : %d\n", __LINE__, len); */
+
+ return len;
+}
+
+static u32 ipc_spi_get_space_vbuff_format_rx(u32 *in_head, u32 *in_tail)
+{
+ u32 space = 0;
+
+ ipc_spi_get_pointer_of_vbuff_format_rx(in_head, in_tail);
+
+ /* check the memory space remained */
+ if (*in_tail <= *in_head)
+ space = FMT_SZ - *in_head + *in_tail;
+ else
+ space = *in_tail - *in_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get FMT rx space : %d\n", __LINE__, space); */
+
+ return space;
+}
+
+static u32 ipc_spi_get_space_vbuff_raw_rx(u32 *in_head, u32 *in_tail)
+{
+ u32 space = 0;
+
+ ipc_spi_get_pointer_of_vbuff_raw_rx(in_head, in_tail);
+
+ /* check the memory space remained */
+ if (*in_tail <= *in_head)
+ space = RAW_SZ - *in_head + *in_tail;
+ else
+ space = *in_tail - *in_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RAW rx space : %d\n", __LINE__, space); */
+
+ return space;
+}
+
+static u32 ipc_spi_get_space_vbuff_rfs_rx(u32 *in_head, u32 *in_tail)
+{
+ u32 space = 0;
+
+ ipc_spi_get_pointer_of_vbuff_rfs_rx(in_head, in_tail);
+
+ /* check the memory space remained */
+ if (*in_tail <= *in_head)
+ space = RFS_SZ - *in_head + *in_tail;
+ else
+ space = *in_tail - *in_head;
+
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) get RFS rx space : %d\n", __LINE__, space); */
+
+ return space;
+}
+
+static int ipc_spi_check_send_data(void)
+{
+ int retval = 0;
+ u32 out_head = 0;
+ u32 out_tail = 0;
+
+#ifdef LOOPBACK_TEST
+ if (loop_back_test)
+ retval = 1;
+#endif
+
+ if (ipc_spi_get_send_vbuff_command())
+ retval = 1;
+
+ ipc_spi_get_pointer_of_vbuff_format_tx(&out_head, &out_tail);
+ if (out_head != out_tail)
+ retval = 1;
+
+ ipc_spi_get_pointer_of_vbuff_raw_tx(&out_head, &out_tail);
+ if (out_head != out_tail)
+ retval = 1;
+
+ ipc_spi_get_pointer_of_vbuff_rfs_tx(&out_head, &out_tail);
+ if (out_head != out_tail)
+ retval = 1;
+
+ return retval;
+}
+
+static void ipc_spi_copy_from_vbuff_format_tx(void *p_des, u32 offset_vbuff, u32 copy_len)
+{
+ if ((offset_vbuff + copy_len) <= FMT_SZ) {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + FMT_OUT + offset_vbuff), copy_len);
+ } else {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + FMT_OUT + offset_vbuff), FMT_SZ - offset_vbuff);
+ memcpy((void *)(p_des + (FMT_SZ - offset_vbuff)), (void *)(p_virtual_buff + FMT_OUT), copy_len - (FMT_SZ - offset_vbuff));
+ }
+}
+
+static void ipc_spi_copy_from_vbuff_raw_tx(void *p_des, u32 offset_vbuff, u32 copy_len)
+{
+ if ((offset_vbuff + copy_len) <= RAW_SZ) {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RAW_OUT + offset_vbuff), copy_len);
+ } else {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RAW_OUT + offset_vbuff), RAW_SZ - offset_vbuff);
+ memcpy((void *)(p_des + (RAW_SZ - offset_vbuff)), (void *)(p_virtual_buff + RAW_OUT), copy_len - (RAW_SZ - offset_vbuff));
+ }
+}
+
+static void ipc_spi_copy_from_vbuff_rfs_tx(void *p_des, u32 offset_vbuff, u32 copy_len)
+{
+ if ((offset_vbuff + copy_len) <= RFS_SZ) {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RFS_OUT + offset_vbuff), copy_len);
+ } else {
+ memcpy((void *)p_des, (void *)(p_virtual_buff + RFS_OUT + offset_vbuff), RFS_SZ - offset_vbuff);
+ memcpy((void *)(p_des + (RFS_SZ - offset_vbuff)), (void *)(p_virtual_buff + RFS_OUT), copy_len - (RFS_SZ - offset_vbuff));
+ }
+}
+
+#ifdef LOOPBACK_TEST
+static void ipc_spi_prepare_tx_data(u8 *tx_b)
+{
+ u32 len = 0, tx_b_remail_len = DEF_BUF_SIZE, read_size = 0;
+ struct spi_protocol_header *tx_header = (struct spi_protocol_header *)tx_b;
+ u32 cmd = 0;
+ u8 cmd_8 = 0;
+ u16 mux = 0;
+ u16 p_tx_b = sizeof(struct spi_protocol_header);
+ u32 p_send_data_h = 0, p_send_data_t = 0;
+ u16 pkt_fmt_len = 0;
+ u32 pkt_len = 0;
+ u8 bof = 0, eof = 0;
+ int i;
+
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ cmd = ipc_spi_get_send_vbuff_command(); /* check mailbox command data */
+ if (cmd) {
+ cmd_8 = cmd & 0xFF;
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>exist CMD cmd_8 : %x\n", __LINE__, cmd_8);
+
+ mux = 0x0004;
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header)), (void *)&mux, sizeof(mux));
+
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux)), (void *)&cmd_8, sizeof(cmd_8));
+ ipc_spi_set_send_vbuff_command_clear();
+
+ tx_header->current_data_size = sizeof(mux) + sizeof(cmd_8);
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+
+ if (ipc_spi_check_send_data())
+ tx_header->more = 1;
+ else
+ tx_header->more = 0;
+
+ } else { /* check format, raw, rfs data */
+ len = ipc_spi_get_length_vbuff_format_tx(&p_send_data_h, &p_send_data_t); /* len : vbuff_format_tx length */
+ if (len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>prepare FMT data\n", __LINE__);
+
+ mux = 0x0001;
+ read_size = 0;
+
+ while (len > read_size) { /* till len is zero */
+ /* bof : 0x7F check */
+ ipc_spi_copy_from_vbuff_format_tx((void *)&bof, p_send_data_t, sizeof(bof));
+
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT bof error, remove invalid data. bof : %x\n", __LINE__, bof);
+
+ ipc_spi_update_tail_of_vbuff_format_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ }
+
+ /* packet length check */
+ ipc_spi_copy_from_vbuff_format_tx((void *)&pkt_fmt_len, p_send_data_t + sizeof(bof), sizeof(pkt_fmt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>FMT packet len : %d\n", __LINE__, pkt_fmt_len);
+
+ if ((pkt_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT wrong packet len, remove invalid data. packet len : %x\n", __LINE__, pkt_fmt_len);
+
+ ipc_spi_update_tail_of_vbuff_format_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ } else if ((pkt_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > tx_b_remail_len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>FMT tx more set\n", __LINE__);
+
+ tx_header->more = 1;
+
+ break;
+ }
+
+ /* make spi tx packet (1 packet : vbuff -> tx_b) */
+ memcpy((void *)(tx_b + p_tx_b), (void *)&mux, sizeof(mux));
+ p_tx_b += sizeof(mux);
+ tx_b_remail_len -= sizeof(mux);
+
+ ipc_spi_copy_from_vbuff_format_tx((void *)(tx_b + p_tx_b), p_send_data_t, pkt_fmt_len + sizeof(bof) + sizeof(eof));
+
+#ifdef FORMAT_TX_DUMP
+ printk(KERN_ERR "[IPC_SPI => FMT TX :");
+ for (i = 0; i < (pkt_fmt_len + sizeof(bof) + sizeof(eof)); i++)
+ printk(KERN_ERR " %02x", *((u8 *)(tx_b + p_tx_b + i)));
+
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_tx_b += pkt_fmt_len + sizeof(bof) + sizeof(eof);
+ p_send_data_t += pkt_fmt_len + sizeof(bof) + sizeof(eof);
+ tx_b_remail_len -= pkt_fmt_len + sizeof(bof) + sizeof(eof);
+
+ p_send_data_t %= FMT_SZ;
+ ipc_spi_update_tail_of_vbuff_format_tx(p_send_data_t); /* in-pointer update */
+
+ read_size += pkt_fmt_len + sizeof(bof) + sizeof(eof);
+ if (len < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) FMT tx read error len : %d, read_size : %d\n", __LINE__, len, read_size);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>FMT len : %d\n", __LINE__, len);
+ }
+
+ tx_header->current_data_size = DEF_BUF_SIZE - tx_b_remail_len;
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+ }
+
+ len = ipc_spi_get_length_vbuff_raw_tx(&p_send_data_h, &p_send_data_t);
+ if (len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>prepare RAW data\n", __LINE__);
+
+ mux = 0x0002;
+ read_size = 0;
+
+ while (len > read_size) { /* till len is zero */
+ /* bof : 0x7F check */
+ ipc_spi_copy_from_vbuff_raw_tx((void *)&bof, p_send_data_t, sizeof(bof));
+
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW bof error, remove invalid data. bof : %x\n", __LINE__, bof);
+
+ ipc_spi_update_tail_of_vbuff_raw_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ }
+
+ /* packet length check */
+ ipc_spi_copy_from_vbuff_raw_tx((void *)&pkt_len, p_send_data_t + sizeof(bof), sizeof(pkt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RAW packet len : %d\n", __LINE__, pkt_len);
+
+ if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW wrong packet len, remove invalid data. packet len : %x\n", __LINE__, pkt_len);
+
+ ipc_spi_update_tail_of_vbuff_raw_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ } else if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > tx_b_remail_len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RAW tx more set\n", __LINE__);
+
+ tx_header->more = 1;
+
+ break;
+ }
+
+ /* make spi tx packet (1 packet : vbuff -> tx_b) */
+ memcpy((void *)(tx_b + p_tx_b), (void *)&mux, sizeof(mux));
+ p_tx_b += sizeof(mux);
+ tx_b_remail_len -= sizeof(mux);
+
+ ipc_spi_copy_from_vbuff_raw_tx((void *)(tx_b + p_tx_b), p_send_data_t, pkt_len + sizeof(bof) + sizeof(eof));
+
+#ifdef RAW_TX_DUMP
+ printk(KERN_ERR "[IPC_SPI => RAW TX :");
+ for (i = 0 ; i < (pkt_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(tx_b + p_tx_b + i)));
+
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_tx_b += pkt_len + sizeof(bof) + sizeof(eof);
+ p_send_data_t += pkt_len + sizeof(bof) + sizeof(eof);
+ tx_b_remail_len -= pkt_len + sizeof(bof) + sizeof(eof);
+
+ p_send_data_t %= RAW_SZ;
+ ipc_spi_update_tail_of_vbuff_raw_tx(p_send_data_t); /* in-pointer update */
+
+ read_size += pkt_len + sizeof(bof) + sizeof(eof);
+ if (len < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) RAW tx read error len : %d, read_size : %d\n", __LINE__, len, read_size);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RAW len : %d\n", __LINE__, len);
+ }
+
+ tx_header->current_data_size = DEF_BUF_SIZE - tx_b_remail_len;
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+ }
+
+ len = ipc_spi_get_length_vbuff_rfs_tx(&p_send_data_h, &p_send_data_t);
+ if (len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>prepare RFS data\n", __LINE__);
+
+ mux = 0x0003;
+ read_size = 0;
+
+ while (len > read_size) { /* till len is zero */
+ /* bof : 0x7F check */
+ ipc_spi_copy_from_vbuff_rfs_tx((void *)&bof, p_send_data_t, sizeof(bof));
+
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS bof error, remove invalid data. bof : %x\n", __LINE__, bof);
+
+ ipc_spi_update_tail_of_vbuff_rfs_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ }
+
+ /* packet length check */
+ ipc_spi_copy_from_vbuff_rfs_tx((void *)&pkt_len, p_send_data_t + sizeof(bof), sizeof(pkt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RFS packet len : %d\n", __LINE__, pkt_len);
+
+ if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS wrong packet len, remove invalid data. packet len : %x\n", __LINE__, pkt_len);
+
+ ipc_spi_update_tail_of_vbuff_rfs_tx(p_send_data_h); /* remove invalid data */
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ return;
+ } else if ((pkt_len + sizeof(bof) + sizeof(eof) + sizeof(mux)) > tx_b_remail_len) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RFS tx more set\n", __LINE__);
+
+ tx_header->more = 1;
+
+ break;
+ }
+
+ /* make spi tx packet (1 packet : vbuff -> tx_b) */
+ memcpy((void *)(tx_b + p_tx_b), (void *)&mux, sizeof(mux));
+ p_tx_b += sizeof(mux);
+ tx_b_remail_len -= sizeof(mux);
+
+ ipc_spi_copy_from_vbuff_rfs_tx((void *)(tx_b + p_tx_b), p_send_data_t, pkt_len + sizeof(bof) + sizeof(eof));
+
+#ifdef RFS_TX_DUMP
+ printk(KERN_ERR "[IPC_SPI => RFS TX :");
+ for (i = 0 ; i < (pkt_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(tx_b + p_tx_b + i)));
+
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_tx_b += pkt_len + sizeof(bof) + sizeof(eof);
+ p_send_data_t += pkt_len + sizeof(bof) + sizeof(eof);
+ tx_b_remail_len -= pkt_len + sizeof(bof) + sizeof(eof);
+
+ p_send_data_t %= RFS_SZ;
+ ipc_spi_update_tail_of_vbuff_rfs_tx(p_send_data_t); /* in-pointer update */
+
+ read_size += pkt_len + sizeof(bof) + sizeof(eof);
+ if (len < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) RFS tx read error len : %d, read_size : %d\n", __LINE__, len, read_size);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) =>RFS len : %d\n", __LINE__, len);
+
+#ifdef RFS_TX_RX_LENGTH_DUMP
+ printk(KERN_ERR "[IPC_SPI => RFS TX : %d]\n", pkt_len);
+#endif
+ }
+
+ tx_header->current_data_size = DEF_BUF_SIZE - tx_b_remail_len;
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+ }
+ }
+
+#ifndef LOOPBACK_TEST
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] TX : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ tx_b[0], tx_b[1], tx_b[2], tx_b[3], tx_b[4], tx_b[5], tx_b[6], tx_b[7], tx_b[8], tx_b[9], tx_b[10], tx_b[11], tx_b[12], tx_b[13], tx_b[14], tx_b[15], tx_b[16], tx_b[17], tx_b[18], tx_b[19],
+ tx_b[20], tx_b[21], tx_b[22], tx_b[23], tx_b[24], tx_b[25], tx_b[26], tx_b[27], tx_b[28], tx_b[29], tx_b[30], tx_b[31], tx_b[32], tx_b[33], tx_b[34], tx_b[35], tx_b[36], tx_b[37], tx_b[38], tx_b[39]);
+#endif
+}
+
+static void ipc_spi_prepare_loopback_tx_data(u8 *tx_b, u8 *rx_b, u8 *test_data)
+{
+ struct spi_protocol_header *tx_header = (struct spi_protocol_header *)tx_b;
+ u16 mux = 0;
+ u8 bof = 0x7F, eof = 0x7E;
+ u16 pkt_len = LOOP_SIZE - 8;
+ u16 ipc_len = pkt_len - 3;
+ u32 ipc_header = 0x010B0A00;
+
+ int i;
+
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ mux = 0x0001;
+
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header)), (void *)&mux, sizeof(mux));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux)), (void *)&bof, sizeof(bof));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof)), (void *)&pkt_len, sizeof(pkt_len));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + 1), (void *)&ipc_len, sizeof(ipc_len));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + 4), (void *)&ipc_header, sizeof(ipc_header));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + 4 + 4), (void *)test_data, LOOP_SIZE-18);
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + pkt_len), (void *)&eof, sizeof(eof));
+
+ tx_header->current_data_size = sizeof(mux) + sizeof(bof) + pkt_len + sizeof(eof);
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+
+ printk(KERN_ERR "[SPI DUMP] LOOP TX :]");
+ for (i = 0 ; i < 30 ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(tx_b + i)));
+ printk(KERN_ERR "| ");
+ for (i = LOOP_SIZE - 30 ; i < LOOP_SIZE ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(tx_b + i)));
+ printk(KERN_ERR "]\n");
+
+}
+#endif
+
+#if 0
+static void ipc_spi_prepare_loopback_tx_data(u8 *tx_b, u8 *rx_b)
+{
+ struct spi_protocol_header *tx_header = (struct spi_protocol_header *)tx_b;
+ u16 mux = 0;
+ u8 bof = 0x7F, eof = 0x7E;
+ u32 pkt_len = 16;
+ u8 test_data[10] = "0123456789";
+ u8 ch_id = 31, control_id = 0;
+
+ int i;
+
+ memset((void *)tx_b, 0, DEF_BUF_SIZE + 4);
+
+ mux = 0x0002;
+
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header)), (void *)&mux, sizeof(mux));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux)), (void *)&bof, sizeof(bof));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof)), (void *)&pkt_len, sizeof(pkt_len));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len)),
+ (void *)&ch_id, sizeof(ch_id));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len) + sizeof(ch_id)),
+ (void *)&control_id, sizeof(control_id));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + sizeof(pkt_len)
+ + sizeof(ch_id) + sizeof(control_id)), (void *)&test_data, sizeof(test_data));
+ memcpy((void *)(tx_b + sizeof(struct spi_protocol_header) + sizeof(mux) + sizeof(bof) + pkt_len), (void *)&eof, sizeof(eof));
+
+ tx_header->current_data_size = sizeof(mux) + sizeof(bof) + pkt_len + sizeof(eof);
+ tx_header->next_data_size = DEF_BUF_SIZE >> 2;
+
+ printk(KERN_ERR "[SPI DUMP] LOOP TX : ");
+ for (i = 0 ; i < 30 ; i++)
+ printk(KERN_ERR "%02x ", tx_b[i]);
+ printk(KERN_ERR "\n");
+}
+#endif
+
+static void ipc_spi_set_MRDY_pin(int val)
+{
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) set MRDY %d\n", __LINE__, val); */
+
+ gpio_set_value(gpio_mrdy, val);
+}
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+int ipc_spi_tx_rx_sync(u8 *tx_d, u8 *rx_d, unsigned len)
+{
+ struct spi_transfer t;
+ struct spi_message msg;
+
+ memset(&t, 0, sizeof t);
+
+ t.len = len;
+
+ t.tx_buf = tx_d;
+ t.rx_buf = rx_d;
+
+ t.cs_change = 0;
+
+ t.bits_per_word = 32;
+ t.speed_hz = 12000000;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&t, &msg);
+
+ return spi_sync(p_ipc_spi, &msg);
+}
+
+static void ipc_spi_swap_data_htn(u8 *data, int len)
+{
+ int i;
+
+ for (i = 0 ; i < len ; i += 4)
+ *(u32 *)(data + i) = htonl(*(u32 *)(data + i));
+}
+
+static void ipc_spi_swap_data_nth(u8 *data, int len)
+{
+ int i;
+
+ for (i = 0 ; i < len ; i += 4)
+ *(u32 *)(data + i) = ntohl(*(u32 *)(data + i));
+}
+
+static int ipc_spi_copy_to_vbuff_format_rx(void *data, u16 len)
+{
+ u32 head = 0, tail = 0, new_head = 0, space = 0;
+ int copy_retry_count = 0;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to FMT vbuff, len : %d\n", __LINE__, len);
+
+COPY_TO_VBUFF_FMT_RETRY:
+
+ space = ipc_spi_get_space_vbuff_format_rx(&head, &tail);
+ if (space < len) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT vbuff is full, space : %d, len : %d\n", __LINE__, space, len);
+
+ copy_retry_count++;
+ if (copy_retry_count > 20) {
+ dev_err(&p_ipc_spi->dev, "(%d) FMT vbuff is full. copy fail.\n", __LINE__);
+
+ return -ENOMEM;
+ }
+
+ msleep(20);
+ goto COPY_TO_VBUFF_FMT_RETRY;
+ }
+
+ if (head + len <= FMT_SZ) {
+ memcpy((void *)(p_virtual_buff + FMT_IN + head), data, len);
+ } else {
+ memcpy((void *)(p_virtual_buff + FMT_IN + head), data, FMT_SZ - head);
+ memcpy((void *)(p_virtual_buff + FMT_IN), (void *)(data + (FMT_SZ - head)), len - (FMT_SZ - head));
+ }
+
+ new_head = (head + len) % FMT_SZ;
+ ipc_spi_update_head_of_vbuff_format_rx(new_head);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to FMT vbuff done.\n", __LINE__);
+
+ return 0;
+}
+
+static int ipc_spi_copy_to_vbuff_raw_rx(void *data, u32 len)
+{
+ u32 head = 0, tail = 0, new_head = 0, space = 0;
+ int copy_retry_count = 0;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RAW vbuff, len : %d\n", __LINE__, len);
+
+COPY_TO_VBUFF_RAW_RETRY:
+
+ space = ipc_spi_get_space_vbuff_raw_rx(&head, &tail);
+ if (space < len) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW vbuff is full, space : %d, len : %d\n", __LINE__, space, len);
+
+ copy_retry_count++;
+ if (copy_retry_count > 20) {
+ dev_err(&p_ipc_spi->dev, "(%d) RAW vbuff is full. copy fail.\n", __LINE__);
+
+ return -ENOMEM;
+ }
+
+ msleep(20);
+ goto COPY_TO_VBUFF_RAW_RETRY;
+ }
+
+ if (head + len <= RAW_SZ) {
+ memcpy((void *)(p_virtual_buff + RAW_IN + head), data, len);
+ } else {
+ memcpy((void *)(p_virtual_buff + RAW_IN + head), data, RAW_SZ - head);
+ memcpy((void *)(p_virtual_buff + RAW_IN), (void *)(data + (RAW_SZ - head)), len - (RAW_SZ - head));
+ }
+
+ new_head = (head + len) % RAW_SZ;
+ ipc_spi_update_head_of_vbuff_raw_rx(new_head);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RAW vbuff done.\n", __LINE__);
+
+ return 0;
+}
+
+static int ipc_spi_copy_to_vbuff_rfs_rx(void *data, u32 len)
+{
+ u32 head = 0, tail = 0, new_head = 0, space = 0;
+ int copy_retry_count = 0;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RFS vbuff, len : %d\n", __LINE__, len);
+
+COPY_TO_VBUFF_RFS_RETRY:
+
+ space = ipc_spi_get_space_vbuff_rfs_rx(&head, &tail);
+ if (space < len) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS vbuff is full, space : %d, len : %d\n", __LINE__, space, len);
+
+ copy_retry_count++;
+ if (copy_retry_count > 20) {
+ dev_err(&p_ipc_spi->dev, "(%d) RFS vbuff is full. copy fail.\n", __LINE__);
+
+ return -ENOMEM;
+ }
+
+ msleep(20);
+ goto COPY_TO_VBUFF_RFS_RETRY;
+ }
+
+ if (head + len <= RFS_SZ) {
+ memcpy((void *)(p_virtual_buff + RFS_IN + head), data, len);
+ } else {
+ memcpy((void *)(p_virtual_buff + RFS_IN + head), data, RFS_SZ - head);
+ memcpy((void *)(p_virtual_buff + RFS_IN), (void *)(data + (RFS_SZ - head)), len - (RFS_SZ - head));
+ }
+
+ new_head = (head + len) % RFS_SZ;
+ ipc_spi_update_head_of_vbuff_rfs_rx(new_head);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=copy data to RFS vbuff done.\n", __LINE__);
+
+ return 0;
+}
+
+#ifndef FEATURE_SAMSUNG_SPI
+static
+#endif
+void ipc_spi_make_data_interrupt(u32 cmd, struct ipc_spi *od)
+{
+ struct list_head *l;
+ unsigned long flags;
+ u32 mailbox;
+
+ mailbox = cmd;
+ /* dev_dbg(&p_ipc_spi->dev, "(%d) <=make data int : 0x%08x\n", __LINE__, mailbox); */
+
+ if (h_list.len) {
+ spin_lock_irqsave(&h_list.lock, flags);
+ list_for_each(l, &h_list.list) {
+ struct ipc_spi_handler *h = list_entry(l, struct ipc_spi_handler, list);
+
+ if (h->handler)
+ h->handler(mailbox, h->data);
+ }
+ spin_unlock_irqrestore(&h_list.lock, flags);
+
+ spin_lock(&ipc_spi_lock);
+ od->mailbox = mailbox;
+ spin_unlock(&ipc_spi_lock);
+ } else {
+ od->mailbox = mailbox;
+ }
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) <=send data int cmd event\n", __LINE__); */
+
+ wake_up_interruptible(&od->waitq);
+ kill_fasync(&od->async_queue, SIGIO, POLL_IN);
+}
+
+static int rx_prev_data_saved;
+static u16 rx_prev_data_mux;
+static u32 rx_prev_data_size;
+static u32 rx_prev_data_remain;
+
+static void ipc_spi_rx_process(u8 *rx_b, u8 *rx_save_b, struct ipc_spi *od)
+{
+ int retval = 0;
+ struct spi_protocol_header *rx_header = (struct spi_protocol_header *)rx_b;
+ u32 total_size = 0, read_size = 0;
+ u16 packet_fmt_len = 0;
+ u32 packet_len = 0;
+ u8 bof = 0, eof = 0;
+ u16 mux = 0;
+ u16 p_read = 4;
+ u32 int_cmd = 0;
+ int i;
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, more : %d, CTS : %d, current size : %d, next size : %d\n", __LINE__, rx_header->more, rx_header->RTSCTS, rx_header->current_data_size, rx_header->next_data_size); */
+
+ total_size = rx_header->current_data_size;
+
+ while (total_size > read_size) {
+ int_cmd = 0;
+
+ if (!rx_prev_data_saved) {
+ /* check bof : 0x7F */
+ memcpy((void *)&bof, (void *)(rx_b + p_read + sizeof(mux)), sizeof(bof));
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, bof : %x\n", __LINE__, bof); */
+ if (bof != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, bof error : %x\n", __LINE__, bof);
+/*
+ printk(KERN_ERR "[IPC_SPI <= RX :");
+ for (i = 0 ; i < DEF_BUF_SIZE + 4 ; i++) {
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + i)));
+ }
+ printk(KERN_ERR "]\n");
+*/
+ break;
+ }
+ }
+
+ if (!rx_prev_data_saved) {
+ /* read mux */
+ memcpy((void *)&mux, (void *)(rx_b + p_read), sizeof(mux));
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, mux : 0x%04x\n", __LINE__, mux); */
+ if (mux > 0x4 || mux < 0x0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, mux error : %x\n", __LINE__, mux);
+ break;
+ }
+ } else {
+ mux = rx_prev_data_mux;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, prev_mux : %d\n", __LINE__, mux);
+ }
+
+ switch (mux) {
+ case 0x0001:
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, got FMT : %x\n", __LINE__, mux); */
+
+ if (rx_prev_data_saved) {
+ if (rx_prev_data_remain > DEF_BUF_SIZE) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data, FMT saved : %d, remain : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_mux = 0x0001;
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), DEF_BUF_SIZE);
+ rx_prev_data_size += DEF_BUF_SIZE;
+ rx_prev_data_remain -= DEF_BUF_SIZE;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data save, FMT size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), rx_prev_data_remain);
+ p_read += rx_prev_data_remain;
+ read_size += rx_prev_data_remain;
+
+ if (*rx_save_b != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, FMT bof error : %x\n", __LINE__, *rx_save_b);
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ if (*(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1) != 0x7E) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, FMT eof error : %x\n", __LINE__, *(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1));
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_format_rx((void *)rx_save_b, rx_prev_data_size + rx_prev_data_remain);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx prev data, cp -> ap FMT memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) rx prev data, <= one packet FMT read Done. size : %d, total_size : %d, read_size : %d, p_read : %d\n", __LINE__,
+ rx_prev_data_size + rx_prev_data_remain, total_size, read_size, p_read);
+ }
+
+#ifdef FORMAT_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= FMT RX :");
+ for (i = 0 ; i < (rx_prev_data_size + rx_prev_data_remain) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_save_b + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ rx_prev_data_saved = 0;
+ } else {
+ /* read packet len */
+ memcpy((void *)&packet_fmt_len, (void *)(rx_b + p_read + sizeof(mux) + sizeof(bof)), sizeof(packet_fmt_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, FMT pkt len : %d\n", __LINE__, packet_fmt_len);
+/* if (packet_fmt_len > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, FMT pkt len error : %d\n", __LINE__, packet_fmt_len);
+ return;
+ } */
+
+ if ((packet_fmt_len + sizeof(mux) + sizeof(bof) + sizeof(eof)) > (total_size - read_size)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, FMT packet_fmt_len : %d, remain : %d\n", __LINE__, packet_fmt_len, total_size - read_size);
+
+ rx_prev_data_mux = 0x0001;
+
+ memcpy((void *)rx_save_b, (void *)(rx_b + p_read + sizeof(mux)), total_size - read_size - sizeof(mux));
+ rx_prev_data_size = total_size - read_size - sizeof(mux);
+ rx_prev_data_remain = packet_fmt_len + sizeof(bof) + sizeof(eof) - rx_prev_data_size;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data save, FMT size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_format_rx((void *)(rx_b + p_read + sizeof(mux)), packet_fmt_len + sizeof(bof) + sizeof(eof));
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, cp -> ap FMT memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, one packet FMT read Done.\n", __LINE__); */
+ }
+
+#ifdef FORMAT_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= FMT RX :");
+ for (i = 0 ; i < (packet_fmt_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + p_read + sizeof(mux) + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_read += packet_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+ read_size += packet_fmt_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, FMT read size : %d\n", __LINE__, read_size); */
+ }
+
+ /* make data interrupt cmd */
+ int_cmd = MB_DATA(MBD_SEND_FMT);
+ ipc_spi_make_data_interrupt(int_cmd, od);
+ break;
+
+ case 0x0002:
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, got RAW : %x\n", __LINE__, mux); */
+
+ if (rx_prev_data_saved) {
+ if (rx_prev_data_remain > DEF_BUF_SIZE) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data, RAW saved : %d, remain : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_mux = 0x0002;
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), DEF_BUF_SIZE);
+ rx_prev_data_size += DEF_BUF_SIZE;
+ rx_prev_data_remain -= DEF_BUF_SIZE;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data save, RAW size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), rx_prev_data_remain);
+ p_read += rx_prev_data_remain;
+ read_size += rx_prev_data_remain;
+
+ if (*rx_save_b != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RAW bof error : %x\n", __LINE__, *rx_save_b);
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ if (*(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1) != 0x7E) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RAW eof error : %x\n", __LINE__, *(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1));
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_raw_rx((void *)rx_save_b, rx_prev_data_size + rx_prev_data_remain);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx prev data, cp -> ap RAW memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) rx prev data, <= one packet RAW read Done. size : %d, total_size : %d, read_size : %d, p_read : %d\n", __LINE__,
+ rx_prev_data_size + rx_prev_data_remain, total_size, read_size, p_read);
+ }
+
+#ifdef RAW_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RAW RX :");
+ for (i = 0 ; i < (rx_prev_data_size + rx_prev_data_remain) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_save_b + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ rx_prev_data_saved = 0;
+ } else {
+ /* read packet len */
+ memcpy((void *)&packet_len, (void *)(rx_b + p_read + sizeof(mux) + sizeof(bof)), sizeof(packet_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, RAW pkt len : %d\n", __LINE__, packet_len);
+/* if (packet_len > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, RAW pkt len error : %d\n", __LINE__, packet_len);
+ return;
+ } */
+
+ if ((packet_len + sizeof(mux) + sizeof(bof) + sizeof(eof)) > (total_size - read_size)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, RAW packet_len : %d, remain : %d\n", __LINE__, packet_len, total_size - read_size);
+
+ rx_prev_data_mux = 0x0002;
+
+ memcpy((void *)rx_save_b, (void *)(rx_b + p_read + sizeof(mux)), total_size - read_size - sizeof(mux));
+ rx_prev_data_size = total_size - read_size - sizeof(mux);
+ rx_prev_data_remain = packet_len + sizeof(bof) + sizeof(eof) - rx_prev_data_size;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data save, RAW size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_raw_rx((void *)(rx_b + p_read + sizeof(mux)), packet_len + sizeof(bof) + sizeof(eof));
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, cp -> ap RAW memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, one packet RAW read Done.\n", __LINE__); */
+ }
+
+#ifdef RAW_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RAW RX :");
+ for (i = 0 ; i < (packet_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + p_read + sizeof(mux) + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_read += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+ read_size += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, RAW read size : %d\n", __LINE__, read_size); */
+ }
+
+ /* make data interrupt cmd */
+ int_cmd = MB_DATA(MBD_SEND_RAW);
+ ipc_spi_make_data_interrupt(int_cmd, od);
+ break;
+
+ case 0x0003:
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, got RFS : %x\n", __LINE__, mux); */
+
+ if (rx_prev_data_saved) {
+ if (rx_prev_data_remain > DEF_BUF_SIZE) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data, RFS saved : %d, remain : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_mux = 0x0003;
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), DEF_BUF_SIZE);
+ rx_prev_data_size += DEF_BUF_SIZE;
+ rx_prev_data_remain -= DEF_BUF_SIZE;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx 2nd prev data save, RFS size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ memcpy((void *)(rx_save_b + rx_prev_data_size), (void *)(rx_b + 4), rx_prev_data_remain);
+ p_read += rx_prev_data_remain;
+ read_size += rx_prev_data_remain;
+
+ if (*rx_save_b != 0x7F) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RFS bof error : %x\n", __LINE__, *rx_save_b);
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ if (*(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1) != 0x7E) {
+ dev_err(&p_ipc_spi->dev, "(%d) <=rx prev, RFS eof error : %x\n", __LINE__, *(u8 *)(rx_save_b + rx_prev_data_size + rx_prev_data_remain - 1));
+
+ rx_prev_data_saved = 0;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_rfs_rx((void *)rx_save_b, rx_prev_data_size + rx_prev_data_remain);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx prev data, cp -> ap RFS memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) rx prev data, <= one packet RFS read Done. size : %d, total_size : %d, read_size : %d, p_read : %d\n", __LINE__,
+ rx_prev_data_size + rx_prev_data_remain, total_size, read_size, p_read);
+ }
+
+#ifdef RFS_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX :");
+ for (i = 0 ; i < (rx_prev_data_size + rx_prev_data_remain) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_save_b + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+#ifdef RFS_TX_RX_LENGTH_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX : %d]\n", rx_prev_data_size + rx_prev_data_remain);
+#endif
+
+ rx_prev_data_saved = 0;
+ } else {
+ /* read packet len */
+ memcpy((void *)&packet_len, (void *)(rx_b + p_read + sizeof(mux) + sizeof(bof)), sizeof(packet_len));
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, RFS pkt len : %d\n", __LINE__, packet_len);
+/* if (packet_len > DEF_BUF_SIZE) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, RFS pkt len error : %d\n", __LINE__, packet_len);
+ return;
+ } */
+
+ if ((packet_len + sizeof(mux) + sizeof(bof) + sizeof(eof)) > (total_size - read_size)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data, RFS packet_len : %d, remain : %d\n", __LINE__, packet_len, total_size - read_size);
+
+ rx_prev_data_mux = 0x0003;
+
+ memcpy((void *)rx_save_b, (void *)(rx_b + p_read + sizeof(mux)), total_size - read_size - sizeof(mux));
+ rx_prev_data_size = total_size - read_size - sizeof(mux);
+ rx_prev_data_remain = packet_len + sizeof(bof) + sizeof(eof) - rx_prev_data_size;
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx prev data save, RFS size : %d, remain size : %d\n", __LINE__, rx_prev_data_size, rx_prev_data_remain);
+
+ rx_prev_data_saved = 1;
+
+ return;
+ }
+
+ /* copy to v_buff */
+ retval = ipc_spi_copy_to_vbuff_rfs_rx((void *)(rx_b + p_read + sizeof(mux)), packet_len + sizeof(bof) + sizeof(eof));
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, cp -> ap RFS memory FULL!!!.\n", __LINE__);
+ return;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, one packet RFS read Done.\n", __LINE__); */
+ }
+
+#ifdef RFS_RX_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX :");
+ for (i = 0 ; i < (packet_len + sizeof(bof) + sizeof(eof)) ; i++)
+ printk(KERN_ERR " %02x", *((u8 *)(rx_b + p_read + sizeof(mux) + i)));
+ printk(KERN_ERR "]\n");
+#endif
+
+ p_read += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+ read_size += packet_len + sizeof(bof) + sizeof(eof) + sizeof(mux);
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, RFS read size : %d\n", __LINE__, read_size); */
+
+#ifdef RFS_TX_RX_LENGTH_DUMP
+ printk(KERN_ERR "[IPC_SPI <= RFS RX : %d]\n", packet_len);
+#endif
+
+ }
+
+ /* make data interrupt cmd */
+ int_cmd = MB_DATA(MBD_SEND_RFS);
+ ipc_spi_make_data_interrupt(int_cmd, od);
+ break;
+
+ case 0x0004:
+ dev_dbg(&p_ipc_spi->dev, "(%d) <=rx process, got command : %x\n", __LINE__, mux);
+ break;
+
+ default:
+ break;
+ }
+
+ if (total_size < read_size)
+ dev_err(&p_ipc_spi->dev, "(%d) rx process, read error.\n", __LINE__);
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) rx process, LOOP ==== total : %d, read : %d, p_read : %d\n", __LINE__, total_size, read_size, p_read); */
+ }
+}
+
+static int ipc_spi_thread(void *data)
+{
+ struct ipc_spi *od = (struct ipc_spi *)data;
+
+ int retval = 0;
+#ifdef LOOPBACK_TEST
+ u8 *tx_buf = NULL;
+ struct spi_protocol_header *tx_header = NULL;
+ u8 *rx_buf = NULL;
+ struct spi_protocol_header *rx_header = NULL;
+ int skip_SRDY_chk = 0;
+ int clear_tx_buf = 0;
+ u8 *rx_save_buf = NULL;
+ u8 *test_data = NULL;
+ int tx_loopback_data = 1;
+ u8 rx_loopback_data;
+ int i, rx_loopback_count = 0;
+#endif
+
+#if defined(CONFIG_MACH_Q1_BD)
+ u32 val = __raw_readl(S5P_INFORM2);
+
+ if (val == 1) {
+ printk(KERN_ERR "[LPM mode] ipc_spi_thread exit!\n");
+ goto exit;
+ }
+#else
+ if (lpcharge == 1) {
+ printk(KERN_ERR "[LPM mode] ipc_spi_thread exit!\n");
+ goto exit;
+ }
+#endif
+
+ daemonize("ipc_spi_thread");
+
+ printk(KERN_ERR "[%s] ipc_spi_thread start.\n", __func__);
+ boot_done = 1;
+
+ wait_for_completion(&ril_init);
+
+ printk(KERN_ERR "[%s] ril_init completed.\n", __func__);
+
+ if (!p_ipc_spi) {
+ printk(KERN_ERR "[%s] p_ipc_spi is NULL.\n", __func__);
+
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (!p_virtual_buff) {
+ dev_err(&p_ipc_spi->dev, "[%s] p_virtual_buff is NULL.\n", __func__);
+
+ retval = -ENODEV;
+ goto exit;
+ }
+
+#ifdef LOOPBACK_TEST
+ tx_buf = kmalloc(DEF_BUF_SIZE + 4, GFP_ATOMIC);
+ if (!tx_buf) {
+ dev_err(&p_ipc_spi->dev, "[%s] tx_buf kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ tx_header = (struct spi_protocol_header *)tx_buf;
+
+ rx_buf = kmalloc(DEF_BUF_SIZE + 4, GFP_ATOMIC);
+ if (!rx_buf) {
+ dev_err(&p_ipc_spi->dev, "[%s] rx_buf kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ rx_header = (struct spi_protocol_header *)rx_buf;
+
+ rx_save_buf = kmalloc(DEF_BUF_SIZE * 3, GFP_ATOMIC);
+ if (!rx_save_buf) {
+ dev_err(&p_ipc_spi->dev, "[%s] rx_save_buf kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ memset((void *)rx_save_buf, 0, DEF_BUF_SIZE * 3);
+
+ test_data = kmalloc(DEF_BUF_SIZE + 4, GFP_ATOMIC);
+ if (!test_data) {
+ dev_err(&p_ipc_spi->dev, "[%s] test_data kmalloc fail.", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+ memset((void *)test_data, 0, DEF_BUF_SIZE + 4);
+#endif
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) wait 2 sec... srdy : %d\n", __LINE__, gpio_get_value(gpio_srdy));
+ msleep(2000);
+
+ while (gpio_get_value(gpio_srdy))
+ ;
+ dev_dbg(&p_ipc_spi->dev, "(%d) cp booting... Done.\n", __LINE__);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) wait 1 sec...\n", __LINE__);
+ msleep(1000);
+
+ printk(KERN_ERR "[IPC_SPI] Start IPC Communication. MRDY : %d, SRDY : %d\n", gpio_get_value(gpio_mrdy), gpio_get_value(gpio_srdy));
+ sema_init(&srdy_sem, 0);
+
+ ipc_spi_irq_log_flag = 1;
+
+#ifndef LOOPBACK_TEST
+ spi_main(1, od);
+#else
+ while (1) {
+
+ if (!ipc_spi_check_send_data()) { /* no send data */
+ if (down_trylock(&srdy_sem)) { /* no srdy sem */
+ dev_dbg(&p_ipc_spi->dev, "(%d) no data and no sem, wait tx-srdy event.\n", __LINE__);
+
+ transfer_thread_waiting = 1;
+
+ skip_SRDY_chk = 0;
+
+ down(&transfer_event_sem); /* wait event(tx or srdy) */
+ dev_dbg(&p_ipc_spi->dev, "(%d) got tx-srdy event.\n", __LINE__);
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) srdy_sem already exist\n", __LINE__);
+
+ skip_SRDY_chk = 1;
+ clear_tx_buf = 1;
+ }
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) send data exist\n", __LINE__);
+ }
+
+ /* HERE : Got tx data event or Got SRDY isr event */
+ if (gpio_get_value(gpio_mrdy)) {
+ dev_dbg(&p_ipc_spi->dev, "(%d) MRDY HIGH!!!\n", __LINE__);
+
+ ipc_spi_set_MRDY_pin(0);
+ }
+ ipc_spi_set_MRDY_pin(1);
+
+ do {
+
+ if (clear_tx_buf) {
+ memset((void *)tx_buf, 0, DEF_BUF_SIZE + 4);
+
+ clear_tx_buf = 0;
+ } else {
+ ipc_spi_prepare_tx_data(tx_buf);
+ }
+#ifdef LOOPBACK_TEST
+ if (loop_back_test) {
+ if (tx_header->current_data_size == 0x3) {
+ /*C2 send*/
+ } else {
+ memset((void *)test_data, tx_loopback_data, LOOP_SIZE-18);
+ ipc_spi_prepare_loopback_tx_data(tx_buf, rx_buf , test_data);
+ if (tx_loopback_data == 0x0A) {
+ loop_back_test = 1;
+ tx_loopback_data = 1;
+ } else
+ tx_loopback_data++;
+ }
+ }
+ skip_SRDY_chk = 1; /* AP Only Loopback */
+#endif
+
+ if (!skip_SRDY_chk) {
+RETRY_WAIT_SEM:
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) wait SRDY : %d\n", __LINE__, gpio_get_value(gpio_srdy));
+
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! MRDY : %d, SRDY : %d\n", __LINE__, gpio_get_value(gpio_mrdy), gpio_get_value(gpio_srdy));
+
+ ipc_spi_set_MRDY_pin(0);
+ mdelay(10);
+ ipc_spi_set_MRDY_pin(1);
+
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT Reset!!! MRDY : %d, SRDY : %d\n", __LINE__, gpio_get_value(gpio_mrdy), gpio_get_value(gpio_srdy));
+
+ if (!gpio_get_value(gpio_srdy))
+ goto RETRY_WAIT_SEM;
+ }
+ dev_dbg(&p_ipc_spi->dev, "(%d) got SRDY : %d\n", __LINE__, gpio_get_value(gpio_srdy));
+ } else {
+ dev_dbg(&p_ipc_spi->dev, "(%d) skip wait SRDY.\n", __LINE__);
+
+ skip_SRDY_chk = 0;
+ }
+
+ ipc_spi_swap_data_htn(tx_buf, DEF_BUF_SIZE + 4); /* host to network */
+
+ retval = ipc_spi_tx_rx_sync(tx_buf, rx_buf, DEF_BUF_SIZE + 4);
+ if (retval != 0)
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ else
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+
+ ipc_spi_swap_data_nth(rx_buf, DEF_BUF_SIZE + 4); /* network to host */
+ *(u32 *)tx_header = ntohl(*(u32 *)tx_header);
+
+#ifdef LOOPBACK_TEST
+ printk(KERN_ERR "[SPI DUMP] LOOP RX :]");
+ for (i = 0 ; i < 30 ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(rx_buf + i)));
+
+ printk(KERN_ERR "| ");
+ for (i = LOOP_SIZE - 30 ; i < LOOP_SIZE ; i++)
+ printk(KERN_ERR "%02x ", *((u8 *)(rx_buf + i)));
+
+ printk(KERN_ERR "]\n");
+#else
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] RX : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3], rx_buf[4], rx_buf[5], rx_buf[6], rx_buf[7], rx_buf[8], rx_buf[9], rx_buf[10], rx_buf[11], rx_buf[12], rx_buf[13], rx_buf[14], rx_buf[15], rx_buf[16], rx_buf[17], rx_buf[18], rx_buf[19],
+ rx_buf[20], rx_buf[21], rx_buf[22], rx_buf[23], rx_buf[24], rx_buf[25], rx_buf[26], rx_buf[27], rx_buf[28], rx_buf[29], rx_buf[30], rx_buf[31], rx_buf[32], rx_buf[33], rx_buf[34], rx_buf[35], rx_buf[36], rx_buf[37], rx_buf[38], rx_buf[39]);
+#endif
+
+#ifdef LOOPBACK_TEST
+ /* Loopback test, IPC header[0A 0C 03] */
+ if (rx_buf[14] == 0x0A && rx_buf[15] == 0x0B && rx_buf[16] == 0x01) {
+ rx_loopback_data = rx_buf[17];
+
+ for (i = 0; i < LOOP_SIZE - 18; i++) {
+ if (rx_buf[17+i] != rx_loopback_data) {
+ printk(KERN_ERR "[Loopback] %dth %02x != %02x Invaild data!\n", i, rx_loopback_data, rx_buf[17+i]);
+ goto exit;
+ }
+ }
+ if (i == (LOOP_SIZE-18))
+ printk(KERN_ERR "[Loopback] %02x is OK!\n", rx_loopback_data);
+
+ rx_loopback_count++;
+ if ((rx_loopback_count % 10) == 0 && rx_loopback_data == 0x0A) {
+ tx_loopback_data = 1;
+ loop_back_test = 1;
+ printk(KERN_ERR "[Loopback] rx_loopback_count = %d\n", rx_loopback_count);
+ }
+ rx_header->RTSCTS = 0;
+ rx_header->more = 0;
+ }
+#else
+ if (*(u32 *)rx_header != 0x00000000 && *(u32 *)rx_header != 0xFFFFFFFF) { /* valid spi header */
+/* dev_dbg(&p_ipc_spi->dev, "(%d) got valid rx data.\n", __LINE__); */
+
+ /* RX process */
+ ipc_spi_rx_process(rx_buf, rx_save_buf, od);
+
+ if (rx_header->RTSCTS) { /* modem is not available. */
+ dev_err(&p_ipc_spi->dev, "(%d) rx CTS set.\n", __LINE__);
+
+ clear_tx_buf = 1;
+ }
+
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) got invalid rx data.\n", __LINE__); */
+
+ rx_header->RTSCTS = 0;
+ rx_header->more = 0;
+ }
+#endif
+ dev_dbg(&p_ipc_spi->dev, "(%d) check more, CTS : %d, rx more : %d, tx more : %d\n", __LINE__, rx_header->RTSCTS, rx_header->more, tx_header->more);
+ msleep(2000);
+ } while (rx_header->RTSCTS || rx_header->more || tx_header->more);
+
+ ipc_spi_set_MRDY_pin(0);
+
+/* dev_dbg(&p_ipc_spi->dev, "(%d) LOOP Done ============================\n", __LINE__); */
+ }
+#endif
+
+exit:
+ printk(KERN_ERR "(%d) thread stop.\n", __LINE__);
+
+ return retval;
+}
+
+/* Send SPRD main image through SPI */
+#if defined(CONFIG_CHN_CMCC_SPI_SPRD)
+#define CP_VER_2
+/* #define SPRD_TRANSLATE_PACKET */
+#define SPRD_BLOCK_SIZE 32768
+
+#ifdef CP_VER_2
+enum image_type {
+ MODEM_MAIN,
+ MODEM_DSP,
+ MODEM_NV,
+ MODEM_EFS,
+ MODEM_RUN,
+};
+#else
+enum image_type {
+ MODEM_KERNEL,
+ MODEM_USER,
+ MODEM_DSP,
+ MODEM_NV,
+ MODEM_RUN,
+};
+#endif
+
+struct image_buf {
+ unsigned int length;
+ unsigned int offset;
+ unsigned int address;
+ unsigned char *buf;
+};
+
+struct sprd_image_buf {
+ u8 *tx_b;
+ u8 *rx_b;
+ u8 *encoded_tx_b;
+ u8 *decoded_rx_b;
+
+ int tx_size;
+ int rx_size;
+ int encoded_tx_size;
+ int decoded_rx_size;
+};
+
+/* CRC */
+#define CRC_16_POLYNOMIAL 0x1021
+#define CRC_16_L_POLYNOMIAL 0x8408
+#define CRC_16_L_SEED 0xFFFF
+#define CRC_TAB_SIZE 256 /* 2^CRC_TAB_BITS */
+#define CRC_16_L_OK 0x0
+#define HDLC_FLAG 0x7E
+#define HDLC_ESCAPE 0x7D
+#define HDLC_ESCAPE_MASK 0x20
+#define CRC_CHECK_SIZE 0x02
+
+#define M_32_SWAP(a) { \
+ u32 _tmp; \
+ _tmp = a; \
+ ((u8 *)&a)[0] = ((u8 *)&_tmp)[3]; \
+ ((u8 *)&a)[1] = ((u8 *)&_tmp)[2]; \
+ ((u8 *)&a)[2] = ((u8 *)&_tmp)[1]; \
+ ((u8 *)&a)[3] = ((u8 *)&_tmp)[0]; \
+ }
+
+#define M_16_SWAP(a) { \
+ u16 _tmp; \
+ _tmp = (u16)a; \
+ ((u8 *)&a)[0] = ((u8 *)&_tmp)[1]; \
+ ((u8 *)&a)[1] = ((u8 *)&_tmp)[0]; \
+ }
+
+unsigned int sprd_crc_calc(char *buf_ptr, unsigned int len)
+{
+ unsigned int i;
+ unsigned short crc = 0;
+
+ while (len-- != 0) {
+ for (i = 0x80; i != 0 ; i = i>>1) {
+ if ((crc & 0x8000) != 0) {
+ crc = crc << 1 ;
+ crc = crc ^ 0x1021;
+ } else {
+ crc = crc << 1 ;
+ }
+
+ if ((*buf_ptr & i) != 0)
+ crc = crc ^ 0x1021;
+ }
+ buf_ptr++;
+ }
+
+ return crc;
+
+}
+
+unsigned short sprd_crc_calc_fdl(unsigned short *src, int len)
+{
+ unsigned int sum = 0;
+ unsigned short SourceValue, DestValue;
+ unsigned short lowSourceValue, hiSourceValue;
+
+ /* Get sum value of the source.*/
+ while (len > 1) {
+ SourceValue = *src++;
+ DestValue = 0;
+ lowSourceValue = (SourceValue & 0xFF00) >> 8;
+ hiSourceValue = (SourceValue & 0x00FF) << 8;
+ DestValue = lowSourceValue | hiSourceValue;
+
+ sum += DestValue;
+ len -= 2;
+ }
+
+ if (len == 1)
+ sum += *((unsigned char *) src);
+
+ sum = (sum >> 16) + (sum & 0x0FFFF);
+ sum += (sum >> 16);
+
+ return ~sum;
+}
+
+int encode_msg(struct sprd_image_buf *img, int bcrc)
+{
+ u16 crc; /* CRC value*/
+ u8 *src_ptr; /* source buffer pointer*/
+ int dest_len; /* output buffer length*/
+ u8 *dest_ptr; /* dest buffer pointer*/
+ u8 high_crc, low_crc;
+ register int curr;
+
+ /* CRC Check. */
+ src_ptr = img->tx_b;
+
+ /* CRC Check. */
+ if (bcrc)
+ crc = sprd_crc_calc(src_ptr, img->tx_size);
+ else
+ crc = sprd_crc_calc_fdl((unsigned short *)src_ptr, img->tx_size);
+
+ high_crc = (crc>>8) & 0xFF;
+ low_crc = crc & 0xFF;
+
+ /* Get the total size to be allocated.*/
+ dest_len = 0;
+
+ for (curr = 0; curr < img->tx_size; curr++) {
+ switch (*(src_ptr+curr)) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ dest_len += 2;
+ break;
+ default:
+ dest_len++;
+ break;
+ }
+ }
+
+ switch (low_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ dest_len += 2;
+ break;
+ default:
+ dest_len++;
+ }
+
+ switch (high_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ dest_len += 2;
+ break;
+ default:
+ dest_len++;
+ }
+
+ dest_ptr = kmalloc(dest_len + 2, GFP_ATOMIC);
+ /* Memory Allocate fail.*/
+ if (dest_ptr == NULL)
+ return 0;
+
+ *dest_ptr = HDLC_FLAG;
+ dest_len = 1;
+
+ /* do escape*/
+ for (curr = 0; curr < img->tx_size; curr++) {
+ switch (*(src_ptr+curr)) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ *(dest_ptr + dest_len++) = HDLC_ESCAPE;
+ *(dest_ptr + dest_len++) = *(src_ptr + curr) ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len++) = *(src_ptr + curr);
+ break;
+ }
+ }
+
+ switch (high_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ *(dest_ptr + dest_len++) = HDLC_ESCAPE;
+ *(dest_ptr + dest_len++) = high_crc ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len++) = high_crc;
+ }
+
+ switch (low_crc) {
+ case HDLC_FLAG:
+ case HDLC_ESCAPE:
+ *(dest_ptr + dest_len++) = HDLC_ESCAPE;
+ *(dest_ptr + dest_len++) = low_crc ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len++) = low_crc;
+ }
+
+
+ *(dest_ptr + dest_len++) = HDLC_FLAG;
+
+ memcpy(img->encoded_tx_b, dest_ptr, dest_len);
+ img->encoded_tx_size = dest_len;
+/*
+ LOGD("[In encode_msg dest_ptr]");
+ for (i=0;i<dest_len;i++)
+ LOGD("0x%X", *(dest_ptr+i));
+
+ LOGD("[In encode_msg output_buf]");
+ for (i=0;i<img->encoded_tx_size;i++)
+ LOGD("0x%X", *(img->encoded_tx_b+i));
+*/
+ kfree(dest_ptr);
+ return 1;
+}
+
+int decode_msg(struct sprd_image_buf *img, int bcrc)
+{
+ u16 crc; /* CRC value*/
+ u8 *src_ptr; /* source buffer pointer*/
+ int dest_len; /* output buffer length*/
+ u8 *dest_ptr; /* dest buffer pointer*/
+ register int curr;
+
+ /* Check if exist End Flag.*/
+ src_ptr = img->rx_b;
+
+ dest_len = 0;
+
+ if (img->rx_size < 4)
+ return -1;
+
+ /* Get the total size to be allocated for decoded message.*/
+ for (curr = 1; curr < img->rx_size - 1; curr++) {
+ switch (*(src_ptr + curr)) {
+ case HDLC_ESCAPE:
+ curr++;
+ dest_len++;
+ break;
+ default:
+ dest_len++;
+ break;
+ }
+ }
+
+ /* Allocate meomory for decoded message*/
+ dest_ptr = NULL;
+ dest_ptr = kmalloc(dest_len, GFP_ATOMIC);
+ /* Memory Free fail.*/
+ if (dest_ptr == NULL)
+ return -2;
+
+ memset(dest_ptr, 0, dest_len);
+
+ curr = 0;
+ dest_len = 0;
+ /* Do de-escape.*/
+ for (curr = 1; curr < img->rx_size - 1; curr++) {
+ switch (*(src_ptr + curr)) {
+ case HDLC_ESCAPE:
+ curr++;
+ *(dest_ptr + dest_len) = *(src_ptr + curr) ^ HDLC_ESCAPE_MASK;
+ break;
+ default:
+ *(dest_ptr + dest_len) = *(src_ptr + curr);
+ break;
+ }
+
+ dest_len = dest_len + 1;
+ }
+
+ /* CRC Check. */
+ if (bcrc)
+ crc = sprd_crc_calc(dest_ptr, dest_len);
+ else
+ crc = sprd_crc_calc_fdl((unsigned short *)dest_ptr, dest_len);
+
+ if (crc != CRC_16_L_OK) {
+ dev_err(&p_ipc_spi->dev, "CRC error : 0x%X", crc);
+ kfree(dest_ptr);
+ return -3;
+ }
+
+ memcpy(img->decoded_rx_b, dest_ptr, dest_len - CRC_CHECK_SIZE);
+ img->decoded_rx_size = dest_len - CRC_CHECK_SIZE ;
+/*
+ LOGD("[In decode_msg dest_ptr]");
+ for (i=0;i<dest_len;i++)
+ LOGD("0x%X", *(dest_ptr+i));
+
+ LOGD("[In decode_msg output_buf]");
+ for (i=0;i<*img->decoded_rx_size;i++)
+ LOGD("0x%X", *(img->decoded_rx_b+i));
+*/
+ kfree(dest_ptr);
+ return 1;
+}
+
+static int ipc_spi_send_modem_bin_execute_cmd(struct ipc_spi *od, u8 *spi_ptr, u32 spi_size, u16 spi_type, u16 spi_crc, struct sprd_image_buf *sprd_img)
+{
+ int retval;
+ u16 send_packet_size;
+ u8 *send_packet_data;
+ u16 d1_crc;
+ u16 d2_crc = spi_crc;
+ u16 type = spi_type;
+#ifdef SPRD_TRANSLATE_PACKET
+ int i, cnt_7E = 0;
+ int bcrc = 0;
+#endif
+
+ /* D1 */
+ send_packet_size = spi_size; /* u32 -> u16 */
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img->tx_size = 6;
+ memcpy(sprd_img->tx_b, &send_packet_size, sizeof(send_packet_size));
+ *(sprd_img->tx_b+2) = 0x00; *(sprd_img->tx_b+3) = 0x00; /* reserved 4 bytes */
+ *(sprd_img->tx_b+4) = 0x00; *(sprd_img->tx_b+5) = 0x00;
+
+ d1_crc = sprd_crc_calc_fdl((unsigned short *)sprd_img->tx_b, sprd_img->tx_size);
+ M_16_SWAP(d1_crc);
+ memcpy((sprd_img->tx_b+6), &d1_crc, sizeof(d1_crc));
+ sprd_img->tx_size += 2;
+#else
+ sprd_img->tx_size = 6;
+ M_16_SWAP(d2_crc);
+ memcpy(sprd_img->tx_b, &send_packet_size, sizeof(send_packet_size));
+ memcpy((sprd_img->tx_b+2), &type, sizeof(type));
+ memcpy((sprd_img->tx_b+4), &d2_crc, sizeof(d2_crc));
+
+ d1_crc = sprd_crc_calc_fdl((unsigned short *)sprd_img->tx_b, sprd_img->tx_size);
+ M_16_SWAP(d1_crc);
+ memcpy((sprd_img->tx_b+6), &d1_crc, sizeof(d1_crc));
+ sprd_img->tx_size += 2;
+#endif
+/*
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] TX_D1(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->tx_size,
+ sprd_img->tx_b[0], sprd_img->tx_b[1], sprd_img->tx_b[2], sprd_img->tx_b[3], sprd_img->tx_b[4],
+ sprd_img->tx_b[5], sprd_img->tx_b[6], sprd_img->tx_b[7]);
+*/
+
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! SRDY : %d, SEM : %d\n", __LINE__, gpio_get_value(gpio_srdy), srdy_sem.count);
+ return -1;
+ }
+
+ retval = ipc_spi_tx_rx_sync(sprd_img->tx_b, sprd_img->rx_b, sprd_img->tx_size);
+ if (retval != 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ return -1;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+ }
+/*
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] TX_D2(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ send_packet_size, spi_ptr[0], spi_ptr[1], spi_ptr[2], spi_ptr[3], spi_ptr[4],
+ spi_ptr[5], spi_ptr[6], spi_ptr[7], spi_ptr[8], spi_ptr[9],
+ spi_ptr[10], spi_ptr[11], spi_ptr[12], spi_ptr[13], spi_ptr[14],
+ spi_ptr[15], spi_ptr[16], spi_ptr[17], spi_ptr[18], spi_ptr[19],
+ spi_ptr[send_packet_size - 10], spi_ptr[send_packet_size - 9], spi_ptr[send_packet_size - 8], spi_ptr[send_packet_size - 7], spi_ptr[send_packet_size - 6],
+ spi_ptr[send_packet_size - 5], spi_ptr[send_packet_size - 4], spi_ptr[send_packet_size - 3], spi_ptr[send_packet_size - 2], spi_ptr[send_packet_size - 1]);
+*/
+ if ((type == 0x0003) || (type == 0x0004)) {
+ printk(KERN_ERR "D2 Skip!!\n");
+ goto ACK;
+ }
+
+ /* D2 */
+ send_packet_data = spi_ptr;
+
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! SRDY : %d, SEM : %d\n", __LINE__, gpio_get_value(gpio_srdy), srdy_sem.count);
+ return -1;
+ }
+
+ retval = ipc_spi_tx_rx_sync(send_packet_data, sprd_img->rx_b, send_packet_size);
+ if (retval != 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ return -1;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+ }
+
+ACK:
+
+ if (is_cp_reset) {
+ while (!gpio_get_value(gpio_srdy))
+ ;
+ } else {
+ if (down_timeout(&srdy_sem, 2 * HZ)) {
+ dev_err(&p_ipc_spi->dev, "(%d) SRDY TimeOUT!!! SRDY : %d, SEM : %d\n", __LINE__, gpio_get_value(gpio_srdy), srdy_sem.count);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] TX_D1(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->tx_size,
+ sprd_img->tx_b[0], sprd_img->tx_b[1], sprd_img->tx_b[2], sprd_img->tx_b[3], sprd_img->tx_b[4],
+ sprd_img->tx_b[5], sprd_img->tx_b[6], sprd_img->tx_b[7]);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] TX_D2(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ send_packet_size, spi_ptr[0], spi_ptr[1], spi_ptr[2], spi_ptr[3], spi_ptr[4],
+ spi_ptr[5], spi_ptr[6], spi_ptr[7]);
+
+ /* WA (CP Reset) jongmoon.suh */
+ if (gpio_get_value(gpio_srdy))
+ ;
+ else
+ return -1;
+
+ }
+ }
+
+ memset(sprd_img->tx_b, 0, SPRD_BLOCK_SIZE+10);
+ retval = ipc_spi_tx_rx_sync(sprd_img->tx_b, sprd_img->rx_b, 8);
+ if (retval != 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ return -1;
+ } else {
+/* dev_dbg(&p_ipc_spi->dev, "(%d) transmit Done.\n", __LINE__); */
+ }
+#ifdef SPRD_TRANSLATE_PACKET
+ for (i = 0; i < 8; i++) {
+ if (*(sprd_img->rx_b+i) == 0x7E)
+ cnt_7E++;
+ if (cnt_7E == 2)
+ break;
+ }
+ sprd_img->rx_size = i + 1;
+/*
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] RX(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->rx_size,
+ sprd_img->rx_b[0], sprd_img->rx_b[1], sprd_img->rx_b[2], sprd_img->rx_b[3], sprd_img->rx_b[4], sprd_img->rx_b[5], sprd_img->rx_b[6], sprd_img->rx_b[7],
+ sprd_img->rx_b[8], sprd_img->rx_b[9], sprd_img->rx_b[10], sprd_img->rx_b[11], sprd_img->rx_b[12], sprd_img->rx_b[13], sprd_img->rx_b[14], sprd_img->rx_b[15]);
+*/
+ if (sprd_img->rx_size != 8) {
+ dev_err(&p_ipc_spi->dev, "ACK size error!, %d\n", sprd_img->rx_size);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] RX(%d) : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n", sprd_img->rx_size,
+ sprd_img->rx_b[0], sprd_img->rx_b[1], sprd_img->rx_b[2], sprd_img->rx_b[3], sprd_img->rx_b[4], sprd_img->rx_b[5], sprd_img->rx_b[6], sprd_img->rx_b[7],
+ sprd_img->rx_b[8], sprd_img->rx_b[9], sprd_img->rx_b[10], sprd_img->rx_b[11], sprd_img->rx_b[12], sprd_img->rx_b[13], sprd_img->rx_b[14], sprd_img->rx_b[15]);
+
+ return -1;
+ }
+ retval = decode_msg(sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "decode_msg(ACK) error!\n");
+ return -1;
+ }
+#else
+ memcpy(sprd_img->decoded_rx_b, sprd_img->rx_b, 4);
+#endif
+ if ((*(sprd_img->decoded_rx_b+0) == 0x00) && (*(sprd_img->decoded_rx_b+1) == 0x80) &&
+ (*(sprd_img->decoded_rx_b+2) == 0x00) && (*(sprd_img->decoded_rx_b+3) == 0x00)) {
+ /* dev_dbg(&p_ipc_spi->dev, "[SPRD] CP sent ACK"); */
+ } else {
+ dev_err(&p_ipc_spi->dev, "Transfer ACK error!srdy_sem = %d\n", srdy_sem.count);
+ dev_err(&p_ipc_spi->dev, "[SPI DUMP] RX : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ sprd_img->rx_b[0], sprd_img->rx_b[1], sprd_img->rx_b[2], sprd_img->rx_b[3], sprd_img->rx_b[4], sprd_img->rx_b[5], sprd_img->rx_b[6], sprd_img->rx_b[7],
+ sprd_img->rx_b[8], sprd_img->rx_b[9], sprd_img->rx_b[10], sprd_img->rx_b[11], sprd_img->rx_b[12], sprd_img->rx_b[13], sprd_img->rx_b[14], sprd_img->rx_b[15]);
+
+ return -1;
+ }
+
+ return retval;
+
+}
+
+static int ipc_spi_send_modem_bin_xmit_img(struct ipc_spi *od, enum image_type type, struct image_buf *img)
+{
+ int retval = 0;
+ struct sprd_image_buf sprd_img;
+ unsigned int data_size;
+ unsigned int send_size = 0;
+ unsigned int rest_size = 0;
+ unsigned int spi_size = 0;
+ unsigned int address;
+ unsigned int fdl1_size;
+ /* No Translate */
+ u16 crc = 0;
+ u16 spi_type = 0;
+
+ unsigned char *spi_ptr;
+ unsigned char *ptr;
+ int i, j;
+#ifdef SPRD_TRANSLATE_PACKET
+ int bcrc = 0;
+#endif
+ u16 sprd_packet_size = SPRD_BLOCK_SIZE;
+
+ sprd_img.tx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.tx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) tx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.tx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ sprd_img.rx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.rx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) rx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.rx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ sprd_img.encoded_tx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.encoded_tx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) encoded_tx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.encoded_tx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ sprd_img.decoded_rx_b = kmalloc(SPRD_BLOCK_SIZE*2, GFP_ATOMIC);
+ if (!sprd_img.decoded_rx_b) {
+ dev_err(&p_ipc_spi->dev, "(%d) encoded_rx_b kmalloc fail.", __LINE__);
+ return -1;
+ }
+ memset(sprd_img.decoded_rx_b, 0, SPRD_BLOCK_SIZE*2);
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img type : %d.\n", __LINE__, type);
+ memcpy(&fdl1_size, (void *)(p_virtual_buff + 4), 4);
+
+ switch (type) {
+#ifdef CP_VER_2
+ case MODEM_MAIN:
+ memcpy(&img->address, (void *)(p_virtual_buff + 8), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 12), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + 0x30 + fdl1_size);
+ img->offset = img->length + fdl1_size + 0x30;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save MAIN to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_DSP:
+ memcpy(&img->address, (void *)(p_virtual_buff + 16), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 20), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save DSP to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_NV:
+ memcpy(&img->address, (void *)(p_virtual_buff + 24), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 28), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save NV to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_EFS:
+ memcpy(&img->address, (void *)(p_virtual_buff + 32), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 36), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save EFS to img.\n", __LINE__);
+
+ break;
+#else
+ case MODEM_KERNEL:
+ memcpy(&img->address, (void *)(p_virtual_buff + 8), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 12), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + 0x30 + fdl1_size);
+ img->offset = img->length + fdl1_size + 0x30;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save KERNEL to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_USER:
+ memcpy(&img->address, (void *)(p_virtual_buff + 16), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 20), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save USER to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_DSP:
+ memcpy(&img->address, (void *)(p_virtual_buff + 24), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 28), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save DSP to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_NV:
+ memcpy(&img->address, (void *)(p_virtual_buff + 32), 4);
+ memcpy(&img->length , (void *)(p_virtual_buff + 36), 4);
+ img->buf = (unsigned char *)(p_virtual_buff + img->offset);
+ img->offset += img->length;
+ dev_dbg(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save NV to img.\n", __LINE__);
+
+ break;
+#endif
+ case MODEM_RUN:
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = 4;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x04;
+ *(sprd_img.tx_b+2) = 0x00; *(sprd_img.tx_b+3) = 0x00;
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(Transfer Start) error!");
+ return -1;
+ }
+#else
+ memset(sprd_img.encoded_tx_b, 0, SPRD_BLOCK_SIZE*2);
+ sprd_img.encoded_tx_size = 0;
+ spi_type = 0x0004;
+ crc = 0;
+#endif
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+ return retval;
+
+ default:
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img wrong : %d.", __LINE__, type);
+ return -1;
+ }
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) Start send img. size : %d\n", __LINE__, img->length);
+
+ ptr = img->buf;
+ data_size = sprd_packet_size;
+ rest_size = img->length;
+ address = img->address;
+
+ M_32_SWAP(img->address);
+ M_32_SWAP(img->length);
+
+ /* Send Transfer Start */
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = 12;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x01;
+ *(sprd_img.tx_b+2) = 0x00; *(sprd_img.tx_b+3) = 0x08;
+ memcpy((sprd_img.tx_b+4), &img->address, sizeof(img->address));
+ memcpy((sprd_img.tx_b+8), &img->length, sizeof(img->length));
+
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(Transfer Start) error!");
+ return -1;
+ }
+#else
+ sprd_img.tx_size = 8;
+ memcpy((sprd_img.tx_b+0), &img->address, sizeof(img->address));
+ memcpy((sprd_img.tx_b+4), &img->length, sizeof(img->length));
+
+ spi_type = 0x0001;
+ crc = sprd_crc_calc_fdl((unsigned short *)sprd_img.tx_b, sprd_img.tx_size);
+ memcpy(sprd_img.encoded_tx_b, sprd_img.tx_b, sprd_img.tx_size);
+ sprd_img.encoded_tx_size = sprd_img.tx_size;
+#endif
+
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) [Transfer Start, Type = %d, Packet = %d]\n", __LINE__, type, sprd_packet_size);
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+ M_32_SWAP(img->length);
+
+ /* Send Data */
+ for (i = 0; send_size < img->length; i++) {
+ if (rest_size < sprd_packet_size)
+ data_size = rest_size;
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = sprd_packet_size + 4;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x02; /* type */
+ M_16_SWAP(sprd_packet_size);
+ memcpy((sprd_img.tx_b + 2), &sprd_packet_size, sizeof(sprd_packet_size));
+ M_16_SWAP(sprd_packet_size);
+
+ for (j = 0; j < data_size; j++)
+ *(sprd_img.tx_b+4+j) = *(ptr + j);
+
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(TransferData_%d) error!", i);
+ return -1;
+ }
+#else
+ sprd_img.encoded_tx_size = sprd_packet_size;
+ for (j = 0; j < data_size; j++)
+ *(sprd_img.encoded_tx_b+j) = *(ptr + j);
+
+ spi_type = 0x0002;
+ crc = sprd_crc_calc_fdl((unsigned short *)sprd_img.encoded_tx_b, sprd_img.encoded_tx_size);
+#endif
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d, %d", __LINE__, retval, i);
+ return -1;
+ }
+
+ send_size += data_size;
+ rest_size -= data_size;
+ ptr += data_size;
+
+ if (!(i % 100))
+ dev_dbg(&p_ipc_spi->dev, "(%d) [%d] 0x%x size done, rest size: 0x%x\n", __LINE__, i, send_size, rest_size);
+ }
+
+ /* Send Transfer End */
+#ifdef SPRD_TRANSLATE_PACKET
+ sprd_img.tx_size = 4;
+ *(sprd_img.tx_b+0) = 0x00; *(sprd_img.tx_b+1) = 0x03;
+ *(sprd_img.tx_b+2) = 0x00; *(sprd_img.tx_b+3) = 0x00;
+ retval = encode_msg(&sprd_img, bcrc);
+ if (retval != 1) {
+ dev_err(&p_ipc_spi->dev, "encode_msg(TransferEnd) error!");
+ return -1;
+ }
+#else
+ memset(sprd_img.encoded_tx_b, 0, SPRD_BLOCK_SIZE * 2);
+ sprd_img.encoded_tx_size = 0;
+
+ spi_type = 0x0003;
+ crc = 0;
+#endif
+ spi_ptr = sprd_img.encoded_tx_b;
+ spi_size = sprd_img.encoded_tx_size;
+
+ dev_dbg(&p_ipc_spi->dev, "(%d) [Transfer END]\n", __LINE__);
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, spi_ptr, spi_size, spi_type, crc, &sprd_img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+
+ kfree(sprd_img.tx_b);
+ kfree(sprd_img.rx_b);
+ kfree(sprd_img.encoded_tx_b);
+ kfree(sprd_img.decoded_rx_b);
+
+ return retval;
+
+}
+
+static void ipc_spi_send_modem_bin(struct work_struct *send_modem_w)
+{
+ int retval = 0;
+ u32 int_cmd = 0xABCDABCD;
+ u32 int_cmd_fail = 0xDCBADCBA;
+ struct image_buf img;
+ unsigned long tick1, tick2;
+
+ struct ipc_spi_send_modem_bin_workq_data *smw
+ = container_of(send_modem_w, struct ipc_spi_send_modem_bin_workq_data, send_modem_w);
+ struct ipc_spi *od = smw->od;
+
+ tick1 = jiffies_to_msecs(jiffies);
+
+ dev_dbg(&p_ipc_spi->dev, "[SPI DUMP] p_virtual_buff : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ *(u8 *)(p_virtual_buff), *(u8 *)(p_virtual_buff + 1), *(u8 *)(p_virtual_buff + 2), *(u8 *)(p_virtual_buff + 3), *(u8 *)(p_virtual_buff + 4),
+ *(u8 *)(p_virtual_buff + 5), *(u8 *)(p_virtual_buff + 6), *(u8 *)(p_virtual_buff + 7), *(u8 *)(p_virtual_buff + 8), *(u8 *)(p_virtual_buff + 9),
+ *(u8 *)(p_virtual_buff + 10), *(u8 *)(p_virtual_buff + 11), *(u8 *)(p_virtual_buff + 12), *(u8 *)(p_virtual_buff + 13), *(u8 *)(p_virtual_buff + 14),
+ *(u8 *)(p_virtual_buff + 15), *(u8 *)(p_virtual_buff + 16), *(u8 *)(p_virtual_buff + 17), *(u8 *)(p_virtual_buff + 18), *(u8 *)(p_virtual_buff + 19));
+#ifdef CP_VER_2
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_MAIN, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#else
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_KERNEL, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_USER, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#endif
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_DSP, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#ifdef CP_VER_2
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_EFS, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+#endif
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_RUN, &img);
+ if (retval < 0) {
+ dev_err(&p_ipc_spi->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+
+ send_modem_spi = 0;
+ is_cp_reset = 0;
+ tick2 = jiffies_to_msecs(jiffies);
+ dev_dbg(&p_ipc_spi->dev, "Downloading takes %lu msec\n", (tick2-tick1));
+
+ /* make data interrupt cmd */
+ ipc_spi_make_data_interrupt(int_cmd, od);
+
+ return;
+
+err:
+ /* make data interrupt cmd */
+ ipc_spi_make_data_interrupt(int_cmd_fail, od);
+
+}
+
+#else /*EUR */
+struct ipc_spi_send_modem_bin_header {
+ u16 sot;
+ u16 type;
+ u16 length;
+};
+
+struct ipc_spi_send_modem_bin_footer {
+ u16 crc;
+ u16 eot;
+};
+
+
+static u16 ipc_spi_send_modem_bin_make_crc(u8 *buf)
+{
+ u16 crc = 0;
+ int i;
+ struct ipc_spi_send_modem_bin_header *header = (struct ipc_spi_send_modem_bin_header *)(buf + 4);
+
+ crc += header->type;
+ crc += header->length;
+
+ buf += 4;
+ buf += sizeof(struct ipc_spi_send_modem_bin_header);
+ for (i = 0 ; i < header->length ; i++)
+ crc += *buf++;
+
+ return crc;
+}
+
+#define EBL_PACKET_SIZE 4096
+static int ipc_spi_send_modem_bin_execute_cmd(struct ipc_spi *od, u16 type, u32 len, void *data)
+{
+ int retval = 0;
+ u8 *tx_b = NULL;
+ u8 *rx_b = NULL;
+ struct spi_protocol_header *tx_spi_header = NULL;
+ struct spi_protocol_header *rx_spi_header = NULL;
+ struct ipc_spi_send_modem_bin_header *tx_header = NULL;
+ struct ipc_spi_send_modem_bin_footer *tx_footer = NULL;
+ struct ipc_spi_send_modem_bin_header *rx_header = NULL;
+ struct ipc_spi_send_modem_bin_footer *rx_footer = NULL;
+
+ tx_b = kmalloc(EBL_PACKET_SIZE, GFP_ATOMIC);
+ if (!tx_b) {
+ dev_err(od->dev, "(%d) tx_b kmalloc fail.", __LINE__);
+ return -ENOMEM;
+ }
+ tx_spi_header = (struct spi_protocol_header *)tx_b;
+ tx_header = (struct ipc_spi_send_modem_bin_header *)(tx_b + 4);
+ memset(tx_b, 0, EBL_PACKET_SIZE);
+
+ rx_b = kmalloc(EBL_PACKET_SIZE, GFP_ATOMIC);
+ if (!rx_b) {
+ dev_err(od->dev, "(%d) rx_b kmalloc fail.", __LINE__);
+ return -ENOMEM;
+ }
+ rx_spi_header = (struct spi_protocol_header *)rx_b;
+ rx_header = (struct ipc_spi_send_modem_bin_header *)(rx_b + 4);
+ memset(rx_b, 0, EBL_PACKET_SIZE);
+
+ ipc_spi_set_MRDY_pin(1);
+
+ tx_spi_header->next_data_size = (EBL_PACKET_SIZE - 4) >> 2;
+ tx_spi_header->current_data_size = sizeof(struct ipc_spi_send_modem_bin_header) + len + sizeof(struct ipc_spi_send_modem_bin_footer);
+
+ tx_header->sot = 0x0002;
+ tx_header->type = type;
+ tx_header->length = len;
+
+ memcpy((void *)(tx_b + sizeof(struct ipc_spi_send_modem_bin_header) + 4), data, len);
+
+ tx_footer = (struct ipc_spi_send_modem_bin_footer *)(tx_b + 4 + sizeof(struct ipc_spi_send_modem_bin_header) + len);
+
+ tx_footer->crc = ipc_spi_send_modem_bin_make_crc(tx_b);
+
+ tx_footer->eot = 0x0003;
+/*
+ dev_dbg(od->dev, "[SPI DUMP] tx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ tx_b[0], tx_b[1], tx_b[2], tx_b[3], tx_b[4],
+ tx_b[5], tx_b[6], tx_b[7], tx_b[8], tx_b[9],
+ tx_b[10], tx_b[11], tx_b[12], tx_b[13], tx_b[14],
+ tx_b[15], tx_b[16], tx_b[17], tx_b[18], tx_b[19],
+ tx_b[EBL_PACKET_SIZE - 10], tx_b[EBL_PACKET_SIZE - 9], tx_b[EBL_PACKET_SIZE - 8], tx_b[EBL_PACKET_SIZE - 7], tx_b[EBL_PACKET_SIZE - 6],
+ tx_b[EBL_PACKET_SIZE - 5], tx_b[EBL_PACKET_SIZE - 4], tx_b[EBL_PACKET_SIZE - 3], tx_b[EBL_PACKET_SIZE - 2], tx_b[EBL_PACKET_SIZE - 1]);
+*/
+ ipc_spi_swap_data_htn(tx_b, EBL_PACKET_SIZE);
+
+ down(&srdy_sem);
+
+ retval = ipc_spi_tx_rx_sync(tx_b, rx_b, EBL_PACKET_SIZE);
+ if (retval != 0)
+ dev_err(od->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ else
+ ;/*dev_dbg(od->dev, "(%d) transmit Done.\n", __LINE__); */
+
+/*
+ dev_dbg(od->dev, "[SPI DUMP] rx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_b[0], rx_b[1], rx_b[2], rx_b[3], rx_b[4],
+ rx_b[5], rx_b[6], rx_b[7], rx_b[8], rx_b[9],
+ rx_b[10], rx_b[11], rx_b[12], rx_b[13], rx_b[14],
+ rx_b[15], rx_b[16], rx_b[17], rx_b[18], rx_b[19],
+ rx_b[EBL_PACKET_SIZE - 10], rx_b[EBL_PACKET_SIZE - 9], rx_b[EBL_PACKET_SIZE - 8], rx_b[EBL_PACKET_SIZE - 7], rx_b[EBL_PACKET_SIZE - 6],
+ rx_b[EBL_PACKET_SIZE - 5], rx_b[EBL_PACKET_SIZE - 4], rx_b[EBL_PACKET_SIZE - 3], rx_b[EBL_PACKET_SIZE - 2], rx_b[EBL_PACKET_SIZE - 1]);
+*/
+
+ if (type == 0x0208) /* ReqForceHwReset */
+ return 0;
+
+ memset(tx_b, 0, EBL_PACKET_SIZE);
+ memset(rx_b, 0, EBL_PACKET_SIZE);
+
+ down(&srdy_sem);
+
+ retval = ipc_spi_tx_rx_sync(tx_b, rx_b, EBL_PACKET_SIZE);
+ if (retval != 0)
+ dev_err(od->dev, "(%d) spi sync error : %d\n", __LINE__, retval);
+ else
+ ;/*dev_dbg(od->dev, "(%d) transmit Done.\n", __LINE__); */
+
+ ipc_spi_swap_data_nth(rx_b, EBL_PACKET_SIZE);
+/*
+ dev_dbg(od->dev, "[SPI DUMP] rx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_b[0], rx_b[1], rx_b[2], rx_b[3], rx_b[4],
+ rx_b[5], rx_b[6], rx_b[7], rx_b[8], rx_b[9],
+ rx_b[10], rx_b[11], rx_b[12], rx_b[13], rx_b[14],
+ rx_b[15], rx_b[16], rx_b[17], rx_b[18], rx_b[19],
+ rx_b[EBL_PACKET_SIZE - 10], rx_b[EBL_PACKET_SIZE - 9], rx_b[EBL_PACKET_SIZE - 8], rx_b[EBL_PACKET_SIZE - 7], rx_b[EBL_PACKET_SIZE - 6],
+ rx_b[EBL_PACKET_SIZE - 5], rx_b[EBL_PACKET_SIZE - 4], rx_b[EBL_PACKET_SIZE - 3], rx_b[EBL_PACKET_SIZE - 2], rx_b[EBL_PACKET_SIZE - 1]);
+*/
+ if (rx_header->type != type) {
+ dev_err(od->dev, "(%d) execute cmd ack error : 0x%x(0x%x)\n", __LINE__, rx_header->type, type);
+
+ dev_dbg(od->dev, "[SPI DUMP] rx : [%02x %02x %02x %02x | %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x ... %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ rx_b[0], rx_b[1], rx_b[2], rx_b[3], rx_b[4],
+ rx_b[5], rx_b[6], rx_b[7], rx_b[8], rx_b[9],
+ rx_b[10], rx_b[11], rx_b[12], rx_b[13], rx_b[14],
+ rx_b[15], rx_b[16], rx_b[17], rx_b[18], rx_b[19],
+ rx_b[EBL_PACKET_SIZE - 10], rx_b[EBL_PACKET_SIZE - 9], rx_b[EBL_PACKET_SIZE - 8], rx_b[EBL_PACKET_SIZE - 7], rx_b[EBL_PACKET_SIZE - 6],
+ rx_b[EBL_PACKET_SIZE - 5], rx_b[EBL_PACKET_SIZE - 4], rx_b[EBL_PACKET_SIZE - 3], rx_b[EBL_PACKET_SIZE - 2], rx_b[EBL_PACKET_SIZE - 1]);
+
+ retval = -1;
+ } else {
+/* dev_dbg(od->dev, "(%d) execute cmd ack Done.\n", __LINE__); */
+ }
+
+ ipc_spi_set_MRDY_pin(0);
+
+ return retval;
+}
+
+enum image_type {
+ MODEM_PSI,
+ MODEM_EBL,
+ MODEM_MAIN,
+ MODEM_NV,
+};
+
+struct image_buf {
+ unsigned int length;
+ unsigned char *buf;
+};
+
+#define PSI_OFFSET 0
+#define EBL_OFFSET 0x10000
+#define MAIN_OFFSET 0x28000
+#define NV_OFFSET 0xA00000
+
+#define PSI_LEN (EBL_OFFSET - PSI_OFFSET - 1)
+#define EBL_LEN (MAIN_OFFSET - EBL_OFFSET)
+#define MAIN_LEN (NV_OFFSET - MAIN_OFFSET)
+#define NV_LEN (2 * 1024 * 1024)
+
+#define MAIN_OFFSET_VM 0
+#define NV_OFFSET_VM 0xD80000
+
+#define SPI_SEND_BLOCK_SIZE 4080
+
+static int ipc_spi_send_modem_bin_xmit_img(struct ipc_spi *od, enum image_type type, unsigned int *address)
+{
+ int retval = 0;
+ struct image_buf img;
+ unsigned int data_size;
+ unsigned int send_size = 0;
+ unsigned int rest_size = 0;
+ unsigned char *ptr;
+ int i;
+
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img type : %d.\n", __LINE__, type);
+ switch (type) {
+ case MODEM_MAIN:
+ img.buf = (unsigned char *)(p_virtual_buff + MAIN_OFFSET_VM);
+ img.length = MAIN_LEN;
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save MAIN to img.\n", __LINE__);
+
+ break;
+
+ case MODEM_NV:
+ img.buf = (unsigned char *)(p_virtual_buff + NV_OFFSET_VM);
+ img.length = NV_LEN;
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img save NV to img.\n", __LINE__);
+
+ break;
+
+ default:
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img wrong : %d.", __LINE__, type);
+ return -1;
+ }
+
+ /* Command : ReqFlashSetAddress(0x0802) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0802, sizeof(unsigned int), address);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd Done.\n", __LINE__);
+
+ dev_dbg(od->dev, "(%d) Start send img. size : %d\n", __LINE__, img.length);
+ ptr = img.buf;
+ data_size = SPI_SEND_BLOCK_SIZE;
+ rest_size = img.length;
+
+ for (i = 0 ; send_size < img.length ; i++) {
+ if (rest_size < SPI_SEND_BLOCK_SIZE)
+ data_size = rest_size;
+
+ /* Command : ReqFlashWriteBlock(0x0804) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0804, data_size, ptr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ return -1;
+ }
+
+ send_size += data_size;
+ rest_size -= data_size;
+ ptr += data_size;
+
+ if (!(i % 100))
+ dev_dbg(od->dev, "(%d) [%d] 0x%x size done, rest size: 0x%x\n", __LINE__, i, send_size, rest_size);
+ }
+
+ return retval;
+}
+
+static void ipc_spi_send_modem_bin(struct work_struct *send_modem_w)
+{
+ int retval = 0;
+ u32 int_cmd = 0xABCDABCD;
+ u32 int_cmd_fail = 0xDCBADCBA;
+ struct ipc_spi_send_modem_bin_workq_data *smw
+ = container_of(send_modem_w, struct ipc_spi_send_modem_bin_workq_data, send_modem_w);
+ struct ipc_spi *od = smw->od;
+
+ unsigned int modem_addr = 0x60300000;
+ unsigned int nvm_static_fix_addr = 0x60e80000;
+ unsigned int nvm_static_cal_addr = 0x60f00000;
+ unsigned int nvm_dynamic_addr = 0x60f80000;
+ unsigned int nvm_addr = 0x60C00000;
+ unsigned short sec_end = 0x0000;
+ unsigned int force_hw_reset = 0x00111001;
+
+ u8 *sec_start = NULL;
+
+ dev_dbg(od->dev, "[SPI DUMP] mb : [%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x]\n",
+ *(u8 *)(p_virtual_buff), *(u8 *)(p_virtual_buff + 1), *(u8 *)(p_virtual_buff + 2), *(u8 *)(p_virtual_buff + 3), *(u8 *)(p_virtual_buff + 4),
+ *(u8 *)(p_virtual_buff + 5), *(u8 *)(p_virtual_buff + 6), *(u8 *)(p_virtual_buff + 7), *(u8 *)(p_virtual_buff + 8), *(u8 *)(p_virtual_buff + 9),
+ *(u8 *)(p_virtual_buff + 10), *(u8 *)(p_virtual_buff + 11), *(u8 *)(p_virtual_buff + 12), *(u8 *)(p_virtual_buff + 13), *(u8 *)(p_virtual_buff + 14),
+ *(u8 *)(p_virtual_buff + 15), *(u8 *)(p_virtual_buff + 16), *(u8 *)(p_virtual_buff + 17), *(u8 *)(p_virtual_buff + 18), *(u8 *)(p_virtual_buff + 19));
+
+ /* Command : ReqSecStart(0x0204) */
+ sec_start = kmalloc(2048, GFP_ATOMIC);
+ if (!sec_start) {
+ dev_err(od->dev, "(%d) sec_start kmalloc fail.", __LINE__);
+ goto err;
+ }
+ memset(sec_start, 0, 2048);
+
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0204, 2048, (void *)sec_start);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd Done.\n", __LINE__);
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_MAIN, &modem_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_MAIN Done.\n", __LINE__);
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &nvm_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_NV:nvm_addr Done.\n", __LINE__);
+
+/*
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &nvm_static_cal_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_NV:nvm_static_cal_addr Done.\n", __LINE__);
+
+ retval = ipc_spi_send_modem_bin_xmit_img(od, MODEM_NV, &nvm_dynamic_addr);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_xmit_img MODEM_NV:nvm_dynamic_addr Done.\n", __LINE__);
+*/
+
+ /* Command : ReqSecEnd(0x0205) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0205, sizeof(unsigned short), &sec_end);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd; ReqSecEnd Done.\n", __LINE__);
+
+ /* Command : ReqForceHwReset(0x0208) */
+ retval = ipc_spi_send_modem_bin_execute_cmd(od, 0x0208, sizeof(unsigned int), &force_hw_reset);
+ if (retval < 0) {
+ dev_err(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd fail : %d", __LINE__, retval);
+ goto err;
+ }
+ dev_dbg(od->dev, "(%d) ipc_spi_send_modem_bin_execute_cmd; ReqForceHwReset Done.\n", __LINE__);
+
+ kfree(sec_start);
+
+ ipc_spi_set_MRDY_pin(0);
+
+ ipc_spi_make_data_interrupt(int_cmd, od);
+
+ return;
+
+err:
+ ipc_spi_make_data_interrupt(int_cmd_fail, od);
+}
+#endif
+
+static int __devinit ipc_spi_platform_probe(struct platform_device *pdev)
+{
+ int r;
+ int irq;
+ struct ipc_spi *od = NULL;
+ struct ipc_spi_platform_data *pdata;
+ struct resource *res;
+ struct task_struct *th;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+ pdata = pdev->dev.platform_data;
+ if (!pdata || !pdata->cfg_gpio) {
+ dev_err(&pdev->dev, "No platform data\n");
+ r = -EINVAL;
+ goto err;
+ }
+
+ gpio_mrdy = pdata->gpio_ipc_mrdy;
+ gpio_srdy = pdata->gpio_ipc_srdy;
+
+ dev_dbg(&pdev->dev, "(%d) gpio_mrdy : %d, gpio_srdy : %d(%d)\n", __LINE__, gpio_mrdy, gpio_srdy, gpio_get_value(gpio_srdy));
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "(%d) failed to get irq number\n", __LINE__);
+
+ r = -EINVAL;
+ goto err;
+ }
+ irq = res->start;
+
+ od = kzalloc(sizeof(struct ipc_spi), GFP_KERNEL);
+ if (!od) {
+ dev_err(&pdev->dev, "(%d) failed to allocate device\n", __LINE__);
+
+ r = -ENOMEM;
+ goto err;
+ }
+ ipc_spi = od;
+
+ dev_dbg(&pdev->dev, "(%d) IpcSpi dev: %p\n", __LINE__, od);
+
+ od->base = 0;
+ od->size = 0x1000000; /* 16M */
+ r = _request_mem(od, pdev);
+ if (r)
+ goto err;
+
+ /* init mailbox state before registering irq handler */
+ onedram_init_mailbox();
+
+ _init_data(od);
+
+ printk(KERN_ERR "cfg_gpio run %p\n", pdata);
+
+ pdata->cfg_gpio();
+
+#ifndef FEATURE_SAMSUNG_SPI
+ irq = gpio_to_irq(gpio_srdy);
+ r = request_irq(irq, ipc_spi_irq_handler, IRQF_TRIGGER_RISING, "IPC_SRDY", od);
+ if (r) {
+ dev_err(&pdev->dev, "(%d) Failed to allocate an interrupt: %d\n", __LINE__, irq);
+
+ goto err;
+ }
+ od->irq = irq;
+ enable_irq_wake(irq);
+#endif
+
+ /* Init work structure */
+ ipc_spi_send_modem_work_data = kmalloc(sizeof(struct ipc_spi_send_modem_bin_workq_data), GFP_ATOMIC);
+ if (!ipc_spi_send_modem_work_data) {
+ dev_err(&pdev->dev, "(%d) memory alloc fail\n", __LINE__);
+
+ r = -ENOMEM;
+ goto err;
+ }
+ INIT_WORK(&ipc_spi_send_modem_work_data->send_modem_w, ipc_spi_send_modem_bin);
+
+ r = _register_chrdev(od);
+ if (r) {
+ dev_err(&pdev->dev, "(%d) Failed to register chrdev\n", __LINE__);
+
+ goto err;
+ }
+
+ r = sysfs_create_group(&od->dev->kobj, &ipc_spi_group);
+ if (r) {
+ dev_err(&pdev->dev, "(%d) Failed to create sysfs files\n", __LINE__);
+
+ goto err;
+ }
+ od->group = &ipc_spi_group;
+
+ platform_set_drvdata(pdev, od);
+
+#ifdef FEATURE_SAMSUNG_SPI
+ spi_main_init(pdata);
+#endif
+
+ th = kthread_create(ipc_spi_thread, (void *)od, "ipc_spi_thread");
+ if (IS_ERR(th)) {
+ dev_err(&pdev->dev, "kernel_thread() failed : %d\n", r);
+
+ goto err;
+ }
+ wake_up_process(th);
+
+ dev_info(&pdev->dev, "(%d) platform probe Done.\n", __LINE__);
+
+ return 0;
+
+err:
+ _release(od);
+ return r;
+}
+
+static int __devexit ipc_spi_platform_remove(struct platform_device *pdev)
+{
+ struct ipc_spi *od = platform_get_drvdata(pdev);
+
+ /* TODO: need onedram_resource clean? */
+ _unregister_all_handlers();
+ platform_set_drvdata(pdev, NULL);
+ ipc_spi = NULL;
+ _release(od);
+
+ /* Free work queue data */
+ kfree(ipc_spi_send_modem_work_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ipc_spi_platform_suspend(struct platform_device *pdev, pm_message_t state)
+{
+/* struct onedram *od = platform_get_drvdata(pdev); */
+
+ return 0;
+}
+
+static int ipc_spi_platform_resume(struct platform_device *pdev)
+{
+/* struct onedram *od = platform_get_drvdata(pdev); */
+
+ return 0;
+}
+#else
+# define ipc_spi_platform_suspend NULL
+# define ipc_spi_platform_resume NULL
+#endif
+
+static int ipc_spi_probe(struct spi_device *spi)
+{
+ int retval = 0;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ p_ipc_spi = spi;
+ p_ipc_spi->mode = SPI_MODE_1;
+ p_ipc_spi->bits_per_word = 32;
+
+ retval = spi_setup(p_ipc_spi);
+ if (retval != 0) {
+ printk(KERN_ERR "[%s] spi_setup ERROR : %d\n", __func__, retval);
+
+ return retval;
+ }
+
+ dev_info(&p_ipc_spi->dev, "(%d) spi probe Done.\n", __LINE__);
+
+ return retval;
+}
+
+static int ipc_spi_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct platform_driver ipc_spi_platform_driver = {
+ .probe = ipc_spi_platform_probe,
+ .remove = __devexit_p(ipc_spi_platform_remove),
+ .suspend = ipc_spi_platform_suspend,
+ .resume = ipc_spi_platform_resume,
+ .driver = {
+ .name = DRVNAME,
+ },
+};
+
+static struct spi_driver ipc_spi_driver = {
+ .probe = ipc_spi_probe,
+ .remove = __devexit_p(ipc_spi_remove),
+ .driver = {
+ .name = "ipc_spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+};
+
+int ipc_spi_thread_restart()
+{
+ int retval;
+
+ send_modem_spi = 1;
+ is_cp_reset = 1;
+
+ printk(KERN_ERR "[IPC_SPI] ipc_spi_thread_restart\n");
+
+ spi_set_restart();
+
+ platform_driver_unregister(&ipc_spi_platform_driver);
+
+ retval = platform_driver_register(&ipc_spi_platform_driver);
+ if (retval < 0) {
+ printk(KERN_ERR "[%s] platform_driver_register ERROR : %d\n", __func__, retval);
+
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ return retval;
+}
+EXPORT_SYMBOL(ipc_spi_thread_restart);
+
+static int __init ipc_spi_init(void)
+{
+ int retval = 0;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ retval = spi_register_driver(&ipc_spi_driver);
+ if (retval < 0) {
+ printk(KERN_ERR "[%s] spi_register_driver ERROR : %d\n", __func__, retval);
+
+ goto exit;
+ }
+
+ retval = platform_driver_register(&ipc_spi_platform_driver);
+ if (retval < 0) {
+ printk(KERN_ERR "[%s] platform_driver_register ERROR : %d\n", __func__, retval);
+
+ goto exit;
+ }
+
+ /* creat work queue thread */
+ ipc_spi_wq = create_singlethread_workqueue("ipc_spi_wq");
+
+ if (!ipc_spi_wq) {
+ printk(KERN_ERR "[%s] get workqueue thread fail\n", __func__);
+
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ printk(KERN_ERR "[%s](%d) init Done - 1011260100.\n", __func__, __LINE__);
+
+ return 0;
+
+exit:
+ return retval;
+}
+
+static void __exit ipc_spi_exit(void)
+{
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ spi_unregister_driver(&ipc_spi_driver);
+ platform_driver_unregister(&ipc_spi_platform_driver);
+
+ if (ipc_spi_wq)
+ destroy_workqueue(ipc_spi_wq);
+}
+
+module_init(ipc_spi_init);
+module_exit(ipc_spi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Wonhee Seo <wonhee48.seo@samsung.com>");
+MODULE_DESCRIPTION("IpcSpi driver");
diff --git a/drivers/phone_svn/ipc_spi/spi_app.c b/drivers/phone_svn/ipc_spi/spi_app.c
new file mode 100644
index 0000000..110d193
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_app.c
@@ -0,0 +1,183 @@
+/**************************************************************
+
+ spi_app.c
+
+
+
+ interface spi and app
+
+
+
+ This is MASTER side.
+
+***************************************************************/
+
+
+
+/**************************************************************
+
+ Preprocessor by common
+
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_app.h"
+#include "spi_os.h"
+#include "spi_data.h"
+#include "spi_test.h"
+
+static unsigned int _pack_spi_data(enum SPI_DATA_TYPE_T type, void *buf,
+ void *data, unsigned int length);
+
+
+/**********************************************************
+Prototype void spi_app_receive_msg ( struct spi_os_msg * msg )
+Type function
+Description receive data from spi task message queue and
+ Pack data for spi data.
+ Then inqueue the message to spi_data_queue_XXX_tx
+Param input msg : message received from other task
+Return value (none)
+***********************************************************/
+void spi_receive_msg_from_app(struct spi_os_msg *msg)
+{
+ enum SPI_MAIN_MSG_T type;
+ enum SPI_DATA_QUEUE_TYPE_T q_type;
+ enum SPI_DATA_TYPE_T mux_type;
+ unsigned int in_length = 0, out_length = 0;
+ void *in_buffer = 0;
+ void *out_buffer = 0;
+
+ type = msg->signal_code;
+ in_length = msg->data_length;
+ in_buffer = msg->data;
+
+ switch (type) {
+ case SPI_MAIN_MSG_IPC_SEND:
+ q_type = SPI_DATA_QUEUE_TYPE_IPC_TX;
+ mux_type = SPI_DATA_MUX_IPC;
+ break;
+
+ case SPI_MAIN_MSG_RAW_SEND:
+ q_type = SPI_DATA_QUEUE_TYPE_RAW_TX;
+ mux_type = SPI_DATA_MUX_RAW;
+ break;
+
+ case SPI_MAIN_MSG_RFS_SEND:
+ q_type = SPI_DATA_QUEUE_TYPE_RFS_TX;
+ mux_type = SPI_DATA_MUX_RFS;
+ break;
+
+ default:
+ SPI_OS_ASSERT(("[SPI] spi_app_receive_msg Unknown type"));
+ return;
+ }
+
+ out_buffer = spi_os_malloc(in_length+SPI_DATA_HEADER_SIZE);
+ out_length = _pack_spi_data(mux_type, out_buffer, in_buffer, in_length);
+
+ if (spi_data_inqueue(&spi_queue_info[q_type], out_buffer,
+ out_length) == 0) {
+ SPI_OS_ASSERT(("[SPI] spi_app_receive_msg inqueue[%d] Fail",
+ q_type));
+ }
+
+ spi_os_free(in_buffer);
+ spi_os_free(out_buffer);
+}
+
+
+/**********************************************************
+Prototype void spi_send_msg ( void )
+Type function
+Description Dequeue a spi data from spi_data_queue_XXX_rx
+ Unpack the spi data for ipc, raw or rfs data
+ Send msg to other task until that all queues are empty
+ CP use this functions for other task as below
+ IPC : ipc_cmd_send_queue
+ RAW : data_send_queue
+ RFS : rfs_send_queue
+Param input (none)
+Return value (none)
+***********************************************************/
+void spi_send_msg_to_app(void)
+{
+ u32 int_cmd = 0;
+ struct ipc_spi *od_spi = NULL;
+
+ #define MB_VALID 0x0080
+ #define MB_DATA(x) (MB_VALID | x)
+ #define MBD_SEND_FMT 0x0002
+ #define MBD_SEND_RAW 0x0001
+ #define MBD_SEND_RFS 0x0100
+
+
+ od_spi = ipc_spi;
+
+
+ if (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_IPC_RX) == 0) {
+ int_cmd = MB_DATA(MBD_SEND_FMT);
+ ipc_spi_make_data_interrupt(int_cmd, od_spi);
+ }
+
+ if (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RAW_RX) == 0) {
+ int_cmd = MB_DATA(MBD_SEND_RAW);
+ ipc_spi_make_data_interrupt(int_cmd, od_spi);
+ }
+
+ if (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RFS_RX) == 0) {
+ int_cmd = MB_DATA(MBD_SEND_RFS);
+ ipc_spi_make_data_interrupt(int_cmd, od_spi);
+ }
+}
+
+
+/**********************************************************
+Prototype unsigned int _pack_spi_data (SPI_DATA_TYPE_T type,void * buf, void * data, unsigned int length)
+Type static function
+Description pack data for spi
+Param input type : type of data type
+ buf : address of buffer to be saved
+ data : address of data to pack
+ length : length of input data
+Return value length of packed data
+***********************************************************/
+static unsigned int _pack_spi_data(enum SPI_DATA_TYPE_T type, void *buf,
+ void *data, unsigned int length)
+{
+ char *spi_packet = NULL;
+ unsigned int out_length = 0;
+
+ spi_packet = (char *) buf;
+
+ spi_os_memset((char *)spi_packet, 0x00, (unsigned int)length);
+ spi_os_memset((char *)spi_packet, (unsigned char)SPI_DATA_BOF,
+ SPI_DATA_BOF_SIZE);
+ spi_os_memcpy((char *)spi_packet + SPI_DATA_BOF_SIZE, data, length);
+ spi_os_memset((char *)spi_packet + SPI_DATA_BOF_SIZE + length,
+ (unsigned char)SPI_DATA_EOF, SPI_DATA_EOF_SIZE);
+
+ out_length = SPI_DATA_BOF_SIZE + length + SPI_DATA_EOF_SIZE;
+
+ return out_length;
+}
+
+
+/**********************************************************
+Prototype int spi_app_ready ( void )
+Type function
+Description check if spi initialization is done.
+ Decide it as spi_main_state.
+Param input (none)
+Return value 1 : spi initialization is done.
+ 0 : spi initialization is not done.
+***********************************************************/
+int spi_is_ready(void)
+{
+ if ((spi_main_state == SPI_MAIN_STATE_START) ||
+ (spi_main_state == SPI_MAIN_STATE_END))
+ return 0;
+
+ return 1;
+}
+
diff --git a/drivers/phone_svn/ipc_spi/spi_app.h b/drivers/phone_svn/ipc_spi/spi_app.h
new file mode 100644
index 0000000..70a9d69
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_app.h
@@ -0,0 +1,15 @@
+#ifndef _SPI_APP_H_
+#define _SPI_APP_H_
+
+#include "spi_main.h"
+#include "spi_data.h"
+#include "spi_os.h"
+
+extern void spi_receive_msg_from_app(struct spi_os_msg *msg);
+extern void spi_send_msg_to_app(void);
+extern int spi_is_ready(void);
+
+extern struct ipc_spi *ipc_spi;
+extern void ipc_spi_make_data_interrupt(u32 cmd, struct ipc_spi *od);
+
+#endif
diff --git a/drivers/phone_svn/ipc_spi/spi_data.c b/drivers/phone_svn/ipc_spi/spi_data.c
new file mode 100644
index 0000000..ecd62ab
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_data.c
@@ -0,0 +1,981 @@
+/**************************************************************
+
+ spi_data.c
+
+
+
+ handling spi data
+
+
+
+ This is MASTER side.
+
+***************************************************************/
+
+
+
+/**************************************************************
+
+ Preprocessor by common
+
+***************************************************************/
+
+#include "spi_data.h"
+#include "spi_os.h"
+#include "spi_dev.h"
+
+
+
+/**************************************************************
+
+ Definition of Variables and Functions by common
+
+***************************************************************/
+
+struct spi_data_queue *spi_queue;
+struct spi_data_queue_info *spi_queue_info;
+struct spi_data_div_buf *spi_div_buf;
+
+char *gspi_data_prepare_packet;
+
+char *gspi_data_packet_buf;
+char *gspi_data_sync_buf;
+
+static int _prepare_tx_type_packet(void *buf,
+ struct spi_data_queue_info *queue_info,
+ struct spi_data_div_buf *spi_data_buf,
+ enum SPI_DATA_TYPE_T spi_type);
+static int _spi_data_verify(void *buf, unsigned int mux);
+
+
+/**********************************************************
+
+Prototype void spi_data_queue_init ( void )
+
+Type function
+
+Description init buffer and data variable
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+void spi_data_queue_init(void)
+{
+ int i = 0;
+
+ /* This is defined at ipc_spi.c file and copied. */
+ #define FMT_OUT 0x0FE000
+ #define FMT_IN 0x10E000
+ #define FMT_SZ 0x10000 /* 65536 bytes */
+
+ #define RAW_OUT 0x11E000
+ #define RAW_IN 0x21E000
+ #define RAW_SZ 0x100000 /* 1 MB */
+
+ #define RFS_OUT 0x31E000
+ #define RFS_IN 0x41E000
+ #define RFS_SZ 0x100000 /* 1 MB */
+
+ void *p_virtual_buff;
+ unsigned int buffer_offset[SPI_DATA_QUEUE_TYPE_NB] = {
+ FMT_OUT, FMT_IN, RAW_OUT, RAW_IN, RFS_OUT, RFS_IN};
+
+ p_virtual_buff = ipc_spi_get_queue_buff();
+ spi_queue = p_virtual_buff+sizeof(struct spi_data_queue)*2;
+
+
+ spi_queue_info = (struct spi_data_queue_info *) spi_os_vmalloc(
+ sizeof(struct spi_data_queue_info)*SPI_DATA_QUEUE_TYPE_NB);
+ spi_os_memset(spi_queue_info, 0x00,
+ sizeof(struct spi_data_queue_info)*SPI_DATA_QUEUE_TYPE_NB);
+
+ spi_div_buf = (struct spi_data_div_buf *) spi_os_vmalloc(
+ sizeof(struct spi_data_div_buf)*SPI_DATA_QUEUE_TYPE_NB);
+ spi_os_memset(spi_div_buf, 0x00, sizeof(struct spi_data_div_buf)
+ *SPI_DATA_QUEUE_TYPE_NB);
+ gspi_data_prepare_packet = (char *) spi_os_vmalloc(
+ SPI_DEV_MAX_PACKET_SIZE);
+ gspi_data_packet_buf = (char *) spi_os_malloc(SPI_DEV_MAX_PACKET_SIZE);
+ gspi_data_sync_buf = (char *) spi_os_malloc(SPI_DEV_MAX_PACKET_SIZE);
+
+ for (i = 0 ; i < SPI_DATA_QUEUE_TYPE_NB ; i++) {
+ spi_queue_info[i].header = &spi_queue[i];
+
+ switch (i) {
+ case SPI_DATA_QUEUE_TYPE_IPC_TX:
+ case SPI_DATA_QUEUE_TYPE_IPC_RX:
+ spi_queue_info[i].buf_size = SPI_DATA_IPC_QUEUE_SIZE;
+ spi_queue_info[i].type = SPI_DATA_MUX_IPC;
+ spi_div_buf[i].buffer = (char *)spi_os_vmalloc(
+ SPI_DATA_IPC_DIV_BUFFER_SIZE);
+ break;
+ case SPI_DATA_QUEUE_TYPE_RAW_TX:
+ case SPI_DATA_QUEUE_TYPE_RAW_RX:
+ spi_queue_info[i].buf_size = SPI_DATA_RAW_QUEUE_SIZE;
+ spi_queue_info[i].type = SPI_DATA_MUX_RAW;
+ spi_div_buf[i].buffer = (char *)spi_os_vmalloc(
+ SPI_DATA_RAW_DIV_BUFFER_SIZE);
+ break;
+ case SPI_DATA_QUEUE_TYPE_RFS_TX:
+ case SPI_DATA_QUEUE_TYPE_RFS_RX:
+ spi_queue_info[i].buf_size = SPI_DATA_RFS_QUEUE_SIZE;
+ spi_queue_info[i].type = SPI_DATA_MUX_RFS;
+ spi_div_buf[i].buffer = (char *)spi_os_vmalloc(
+ SPI_DATA_RFS_DIV_BUFFER_SIZE);
+ break;
+ }
+
+ if (spi_queue_info[i].buffer == 0)
+ spi_queue_info[i].buffer =
+ (char *)(p_virtual_buff + buffer_offset[i]);
+ }
+}
+
+
+/**********************************************************
+
+Prototype void spi_data_queue_destroy ( void )
+
+Type function
+
+Description memfree buffer and data variable
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+
+void spi_data_queue_destroy(void)
+{
+ int i = 0;
+
+ if (spi_div_buf != NULL) {
+ for (i = 0 ; i < SPI_DATA_QUEUE_TYPE_NB ; i++) {
+ if (spi_div_buf[i].buffer != NULL) {
+ spi_os_vfree(spi_div_buf[i].buffer);
+ spi_div_buf[i].buffer = NULL;
+ }
+ }
+ }
+
+ if (gspi_data_prepare_packet != NULL) {
+ spi_os_vfree(gspi_data_prepare_packet);
+ gspi_data_prepare_packet = NULL;
+ }
+
+ if (gspi_data_packet_buf != NULL) {
+ spi_os_free(gspi_data_packet_buf);
+ gspi_data_packet_buf = NULL;
+ }
+
+ if (gspi_data_sync_buf != NULL) {
+ spi_os_free(gspi_data_sync_buf);
+ gspi_data_sync_buf = NULL;
+ }
+
+ if (spi_div_buf != NULL) {
+ spi_os_vfree(spi_div_buf);
+ spi_div_buf = NULL;
+ }
+
+ if (spi_queue_info != NULL) {
+ spi_os_vfree(spi_queue_info);
+ spi_queue_info = NULL;
+ }
+}
+
+
+
+/**********************************************************
+
+Prototype int spi_data_inqueue (struct spi_data_queue_info * queue_info,
+ void * data, unsigned int length )
+
+Type function
+
+Description inqueue data to spi rx or tx buffer
+
+Param input queue_info : queue for inqueue
+
+ data : address of data
+
+ lenth : length of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+int spi_data_inqueue(struct spi_data_queue_info *queue_info,
+ void *data, unsigned int length)
+{
+ char *pdata = NULL;
+ struct spi_data_queue *queue = NULL;
+ pdata = data;
+ queue = queue_info->header;
+
+ if (queue->tail < queue->head) {
+ if ((queue->head - queue->tail) < length) {
+ SPI_OS_ASSERT(("%s%s[%u],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_inqueue : ",
+ "queue is overflow head", queue->head,
+ "tail", queue->tail, "length", length,
+ "buf_size", queue_info->buf_size));
+ return 0;
+ }
+ } else {
+ if ((queue_info->buf_size - (queue->tail - queue->head))
+ < length) {
+ SPI_OS_ASSERT(("%s%s[%u],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_inqueue : queue is overflow ",
+ "head", queue->head, "tail", queue->tail,
+ "request length", length,
+ "buf_size", queue_info->buf_size));
+ return 0;
+ }
+ }
+
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_RX] == queue_info) {
+ pdata += (SPI_DATA_MUX_SIZE+SPI_DATA_LENGTH_SIZE);
+ length -= (SPI_DATA_MUX_SIZE+SPI_DATA_LENGTH_SIZE);
+ }
+
+ if (queue_info->buf_size < (queue->tail + length)) {
+ /* maximum < tail + length */
+ unsigned int pre_data_len = 0;
+ pre_data_len = queue_info->buf_size - queue->tail;
+ spi_os_memcpy(queue_info->buffer + queue->tail,
+ pdata, pre_data_len);
+ spi_os_memcpy(queue_info->buffer, pdata + pre_data_len,
+ length - pre_data_len);
+ queue->tail = ((queue->tail+length)%queue_info->buf_size);
+ } else if (queue_info->buf_size == (queue->tail + length)) {
+ /* maximum == tail + length */
+ spi_os_memcpy((queue_info->buffer + queue->tail),
+ (char *)pdata, length);
+ queue->tail = 0;
+ } else {
+ /* maximum > tail + length */
+ spi_os_memcpy((queue_info->buffer + queue->tail),
+ (char *)pdata, length);
+ queue->tail = queue->tail + length;
+ }
+
+ return 1;
+}
+
+
+/**********************************************************
+
+Prototype unsigned int spi_data_dequeue
+ (struct spi_data_queue_info * queue_info, void * pdata)
+
+Type function
+
+Description dequeue data to spi
+
+Param input queue_info : queue for dequeue
+
+ pdata : address of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+unsigned int spi_data_dequeue(struct spi_data_queue_info *queue_info,
+ void *pdata)
+{
+ unsigned int length = 0, buf_length = 0, pre_data_len = 0;
+ struct spi_data_queue *queue = NULL;
+
+ queue = queue_info->header;
+
+ if (queue->tail == queue->head) { /* empty */
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : spi_data_dequeue:",
+ "queue is empty"));
+ return 0;
+ }
+
+ if (queue->head == queue_info->buf_size)
+ queue->head = 0;
+
+ /* check length of data */
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info) {
+ /* IPC Case */
+ if (queue_info->buf_size == (queue->head + SPI_DATA_BOF_SIZE)) {
+ /* maximum == head + pos_len */
+ spi_os_memcpy(&length, queue_info->buffer,
+ SPI_DATA_IPC_INNER_LENGTH_SIZE);
+ } else if (queue_info->buf_size < (queue->head +
+ SPI_DATA_BOF_SIZE +
+ SPI_DATA_IPC_INNER_LENGTH_SIZE)) {
+ /* maximum < head + pos_len */
+ char data_header[SPI_DATA_IPC_INNER_LENGTH_SIZE] = {0,};
+ pre_data_len = queue_info->buf_size - queue->head -
+ SPI_DATA_BOF_SIZE;
+
+ spi_os_memcpy(data_header, (queue_info->buffer +
+ queue->head + SPI_DATA_BOF_SIZE), pre_data_len);
+ spi_os_memcpy(data_header + pre_data_len,
+ queue_info->buffer,
+ SPI_DATA_IPC_INNER_LENGTH_SIZE - pre_data_len);
+ spi_os_memcpy(&length, data_header,
+ SPI_DATA_IPC_INNER_LENGTH_SIZE);
+ } else { /* maximum > head + pos_len */
+ spi_os_memcpy(&length,
+ (queue_info->buffer + queue->head +
+ SPI_DATA_BOF_SIZE),
+ SPI_DATA_IPC_INNER_LENGTH_SIZE);
+ }
+ } else { /* RAW, RFS Case */
+ if (queue_info->buf_size == (queue->head + SPI_DATA_BOF_SIZE)) {
+ /* maximum == head + pos_len */
+ spi_os_memcpy(&length, queue_info->buffer,
+ SPI_DATA_INNER_LENGTH_SIZE);
+ } else if (queue_info->buf_size < (queue->head +
+ SPI_DATA_BOF_SIZE + SPI_DATA_INNER_LENGTH_SIZE)) {
+ /* maximum < head + pos_len */
+ char data_header[SPI_DATA_INNER_LENGTH_SIZE] = {0,};
+ pre_data_len = queue_info->buf_size -
+ queue->head - SPI_DATA_BOF_SIZE;
+
+ spi_os_memcpy(data_header,
+ (queue_info->buffer + queue->head +
+ SPI_DATA_BOF_SIZE),
+ pre_data_len);
+ spi_os_memcpy(data_header + pre_data_len,
+ queue_info->buffer,
+ SPI_DATA_INNER_LENGTH_SIZE - pre_data_len);
+ spi_os_memcpy(&length, data_header,
+ SPI_DATA_INNER_LENGTH_SIZE);
+ } else { /* maximum > head + pos_len */
+ spi_os_memcpy(&length,
+ (queue_info->buffer + queue->head +
+ SPI_DATA_BOF_SIZE),
+ SPI_DATA_INNER_LENGTH_SIZE);
+ }
+ }
+ length += SPI_DATA_BOF_SIZE + SPI_DATA_EOF_SIZE;
+ buf_length = length + SPI_DATA_MUX_SIZE + SPI_DATA_LENGTH_SIZE;
+
+ if (length > SPI_DEV_MAX_PACKET_SIZE) {
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info ||
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX] == queue_info) {
+ /* IPC Case */
+ SPI_OS_ERROR(("%s %s[%x],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue: IPC error",
+ "length", length, "buf_size",
+ queue_info->buf_size, "head",
+ queue->head, "tail", queue->tail));
+ } else if (
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX] == queue_info) {
+ /* RAW Case */
+ SPI_OS_ERROR(("%s %s[%x],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue: RAW error",
+ "length", length,
+ "buf_size", queue_info->buf_size,
+ "head", queue->head, "tail", queue->tail));
+ } else { /* RFS Case */
+ SPI_OS_ERROR(("%s %s[%x],%s[%u],%s[%u],%s[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue: RFS error",
+ "length", length,
+ "buf_size", queue_info->buf_size,
+ "head", queue->head, "tail", queue->tail));
+ }
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->head - 1, 16);
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->tail - 1, 16);
+ return 0;
+ }
+
+ if (&spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX] == queue_info
+ || &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_TX] == queue_info) {
+ unsigned int templength;
+
+ spi_os_memcpy((char *) pdata, &queue_info->type,
+ SPI_DATA_MUX_SIZE);
+ pdata += SPI_DATA_MUX_SIZE;
+ templength = length-SPI_DATA_BOF_SIZE-SPI_DATA_EOF_SIZE;
+ spi_os_memcpy((char *) pdata, &templength,
+ SPI_DATA_LENGTH_SIZE);
+ pdata += SPI_DATA_LENGTH_SIZE;
+ }
+
+ if (queue->tail > queue->head) {
+ if (queue->tail - queue->head < length) {
+ SPI_OS_ERROR(("%s %s tail[%u], head[%u], length[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue:",
+ "request data length is less than queue`s remain data.",
+ queue->tail, queue->head, length));
+
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->head - 1, 16);
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->tail - 1, 16);
+ return 0;
+ }
+ } else if (queue->tail < queue->head) {
+ if ((queue_info->buf_size - queue->head + queue->tail)
+ < length) {
+ SPI_OS_ERROR(("%s %s tail[%u], head[%u], length[%u]\n",
+ "[SPI] ERROR : spi_data_dequeue:",
+ "request data length is less than queue`s remain data.",
+ queue->tail, queue->head, length));
+
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->head - 1, 16);
+ spi_os_trace_dump_low("spi_data_dequeue error",
+ queue_info->buffer + queue->tail - 1, 16);
+ return 0;
+ }
+ }
+
+ if (queue_info->buf_size < (queue->head+length)) {
+ /* maximum < head + length */
+ pre_data_len = queue_info->buf_size - queue->head;
+ spi_os_memcpy((char *)pdata,
+ queue_info->buffer + queue->head, pre_data_len);
+ spi_os_memcpy((char *)pdata + pre_data_len,
+ queue_info->buffer, length - pre_data_len);
+ queue->head = length - pre_data_len;
+ } else if (queue_info->buf_size == (queue->head+length)) {
+ /* maximum = head + length */
+ spi_os_memcpy((char *)pdata,
+ (queue_info->buffer + queue->head), length);
+ queue->head = 0;
+ } else { /* maximum > head + length */
+ spi_os_memcpy((char *)pdata,
+ (queue_info->buffer + queue->head), length);
+ queue->head = queue->head + length;
+ }
+
+ return buf_length;
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_queue_is_empty
+
+Type function
+
+Description check queue space empty or not
+
+Param input type : queue type
+
+Return value 0 : not empty
+
+ 1 : empty
+
+***********************************************************/
+
+int spi_data_queue_is_empty(enum SPI_DATA_QUEUE_TYPE_T type)
+{
+ if (spi_queue[type].head == spi_queue[type].tail)
+ return 1; /* empty */
+ else
+ return 0; /* not empty */
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_div_buf_is_empty
+
+Type function
+
+Description check queue space empty or not
+
+Param input type : queue type
+
+Return value 0 : not empty
+
+ 1 : empty
+
+***********************************************************/
+
+int spi_data_div_buf_is_empty(enum SPI_DATA_QUEUE_TYPE_T type)
+{
+ if (spi_div_buf[type].length > 0)
+ return 0; /* not empty */
+ else
+ return 1; /* Empty */
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_check_tx_queue( void )
+
+Type function
+
+Description check tx queue space empty or not
+
+Param input (none)
+
+Return value 0 : empty
+
+ 1 : data exist
+
+***********************************************************/
+
+int spi_data_check_tx_queue(void)
+{
+ if ((spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_IPC_TX) == 0)
+ || (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RAW_TX) == 0)
+ || (spi_data_queue_is_empty(SPI_DATA_QUEUE_TYPE_RFS_TX) == 0))
+ return 1; /* has data */
+ else if ((spi_data_div_buf_is_empty(SPI_DATA_QUEUE_TYPE_IPC_TX) == 0)
+ || (spi_data_div_buf_is_empty(SPI_DATA_QUEUE_TYPE_RAW_TX) == 0)
+ || (spi_data_div_buf_is_empty(SPI_DATA_QUEUE_TYPE_RFS_TX) == 0))
+ return 1; /* has data */
+ else
+ return 0; /* empty */
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_prepare_tx_packet ( void * buf )
+
+Type function
+
+Description prepare packet for sync. attach spi_data_protocol_header,
+ mux, bof, data and eof
+
+Param input buf : address of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+int spi_data_prepare_tx_packet(void *buf)
+{
+ struct spi_data_queue *queue = NULL;
+ int flag_to_send = 0;
+
+ /* process IPC data */
+ queue = &spi_queue[SPI_DATA_QUEUE_TYPE_IPC_TX];
+ if ((queue->head != queue->tail)
+ || (spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_TX].length > 0)) {
+ if (_prepare_tx_type_packet(buf,
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_TX],
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_TX],
+ SPI_DATA_MUX_IPC) == 0)
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+
+ flag_to_send++;
+ }
+
+ /* process RAW data */
+ queue = &spi_queue[SPI_DATA_QUEUE_TYPE_RAW_TX];
+ if ((queue->head != queue->tail)
+ || (spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_TX].length > 0)) {
+ if (_prepare_tx_type_packet(buf,
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_TX],
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_TX],
+ SPI_DATA_MUX_RAW) == 0)
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+
+ flag_to_send++;
+ }
+
+ /* process RFS data */
+ queue = &spi_queue[SPI_DATA_QUEUE_TYPE_RFS_TX];
+ if ((queue->head != queue->tail)
+ || (spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_TX].length > 0)) {
+ if (_prepare_tx_type_packet(buf,
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_TX],
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_TX],
+ SPI_DATA_MUX_RFS) == 0)
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+
+ flag_to_send++;
+ }
+
+ if (flag_to_send == 0)
+ return 0;
+ else
+ return SPI_DATA_PACKET_HEADER_SIZE +
+ ((struct spi_data_packet_header *)
+ buf)->current_data_size;
+}
+
+
+/**********************************************************
+
+Prototype static int _prepare_tx_type_packet
+
+Type static function
+
+Description prepare spi data for copy to spi packet from rx queue.
+ If spi data bigger than spi packet free size,
+ it need separate and inqueue extra data
+
+Param input buf : address of buffer to be saved
+ queue_info : tx queue for IPC or RAW or RFS
+ spi_data_buf : tx buffer for IPC or RAW or RFS
+
+Return value 0 : buffer full
+
+ (other) : packet size include header and tail
+
+***********************************************************/
+
+static int _prepare_tx_type_packet(void *buf,
+ struct spi_data_queue_info *queue_info,
+ struct spi_data_div_buf *spi_data_buf,
+ enum SPI_DATA_TYPE_T spi_type)
+{
+ char *spi_packet = NULL;
+
+ struct spi_data_packet_header *spi_packet_header = NULL;
+ unsigned int spi_packet_free_length = 0;
+
+ unsigned int cur_dequeue_length = 0;
+ unsigned int spi_packet_count = 0;
+ unsigned int spi_data_mux = 0;
+
+ struct spi_data_queue *queue = NULL;
+
+ queue = queue_info->header;
+
+ spi_packet = (char *)buf;
+ spi_packet_header = (struct spi_data_packet_header *)buf;
+ spi_packet_free_length = SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE -
+ spi_packet_header->current_data_size;
+
+ /* not enough space in spi packet */
+ /* spi_packet_header->current_data_size > 2022(2048 - 16) */
+ if (spi_packet_header->current_data_size >
+ SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE - SPI_DATA_MIN_SIZE) {
+ if (spi_data_check_tx_queue() == 1)
+ spi_packet_header->more = 1;
+ return 0;
+ }
+
+ while ((queue->head != queue->tail) || (spi_data_buf->length > 0)) {
+ spi_os_memset(gspi_data_prepare_packet,
+ 0, SPI_DEV_MAX_PACKET_SIZE);
+ cur_dequeue_length = 0;
+
+ /* dequeue SPI data */
+ if (spi_data_buf->length > 0) {
+ if ((*(unsigned int *)spi_data_buf->buffer)
+ == SPI_DATA_FF_PADDING_HEADER) {
+ /* if data has 0xFF padding header */
+ /* send packet directly */
+ spi_os_memcpy(spi_packet, spi_data_buf->buffer,
+ spi_data_buf->length);
+ spi_data_buf->length = 0;
+ return 0;
+ } else {
+ /* read from tx div buf */
+ spi_os_memcpy(gspi_data_prepare_packet,
+ spi_data_buf->buffer,
+ spi_data_buf->length);
+ cur_dequeue_length = spi_data_buf->length;
+ spi_data_buf->length = 0;
+ }
+ } else {
+ /* read from tx queue */
+ cur_dequeue_length = spi_data_dequeue(queue_info,
+ gspi_data_prepare_packet);
+ }
+
+ if (cur_dequeue_length == 0)
+ continue;
+
+ if (spi_packet_free_length < cur_dequeue_length) {
+ spi_os_memcpy(spi_data_buf->buffer,
+ gspi_data_prepare_packet, cur_dequeue_length);
+ spi_data_buf->length = cur_dequeue_length;
+ spi_packet_header->more = 1;
+ return 0;
+ }
+
+ /* check mux value */
+ spi_os_memcpy(&spi_data_mux, gspi_data_prepare_packet,
+ SPI_DATA_MUX_SIZE);
+ if (spi_data_mux == 0)
+ spi_os_memcpy(gspi_data_prepare_packet,
+ &spi_type, SPI_DATA_MUX_SIZE);
+
+ spi_os_memcpy(spi_packet + SPI_DATA_PACKET_HEADER_SIZE +
+ spi_packet_header->current_data_size,
+ gspi_data_prepare_packet, cur_dequeue_length);
+
+ /* update header */
+ spi_packet_header->current_data_size += cur_dequeue_length;
+ spi_packet_free_length -= cur_dequeue_length;
+
+ /* increase spi packet count */
+ spi_packet_count++;
+
+ /* check spi packet size */
+ if (spi_packet_free_length < SPI_DATA_MIN_SIZE) {
+ if (spi_data_check_tx_queue() == 1)
+ spi_packet_header->more = 1;
+ return 0;
+ }
+
+ /* check spi maximum count per packet */
+ if (spi_packet_count >= SPI_DATA_MAX_COUNT_PER_PACKET) {
+
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : spi _prepare_tx_type_packet :",
+ "spi_packet_count is full"));
+
+ return 0;
+ }
+ }
+
+ return spi_packet_header->current_data_size +
+ SPI_DATA_PACKET_HEADER_SIZE;
+}
+
+
+/**********************************************************
+
+Prototype int spi_data_parsing_rx_packet
+ ( void * buf, unsigned int length )
+
+Type function
+
+Description parsing rx packet for transfer to application. It extract data
+
+ and inqueue each SPI_DATA_TYPE queue
+
+Param input buf : address of buffer to be saved
+
+ lenth : length of data
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+int spi_data_parsing_rx_packet(void *buf, unsigned int length)
+{
+ struct spi_data_packet_header *spi_packet_header = NULL;
+ char *spi_packet = NULL;
+ unsigned int spi_packet_length = 0;
+ unsigned int spi_packet_cur_pos = SPI_DATA_PACKET_HEADER_SIZE;
+
+ unsigned int spi_data_mux = 0;
+ unsigned int spi_data_length = 0;
+ char *spi_cur_data = NULL;
+
+ struct spi_data_queue_info *queue_info = NULL;
+ struct spi_data_div_buf *tx_div_buf = NULL;
+
+
+ /* check spi packet header */
+ if (*(unsigned int *)buf == 0x00000000
+ || *(unsigned int *)buf == 0xFFFFFFFF) {
+ /* if spi header is invalid, */
+ /* read spi header again with next 4 byte */
+ buf += SPI_DATA_PACKET_HEADER_SIZE;
+ }
+
+ spi_packet = (char *) buf;
+
+ /* read spi packet header */
+ spi_packet_header = (struct spi_data_packet_header *) buf;
+ spi_packet_length = SPI_DATA_PACKET_HEADER_SIZE +
+ spi_packet_header->current_data_size;
+
+
+ do {
+ /* read spi data mux and set current queue */
+ spi_os_memcpy(&spi_data_mux,
+ spi_packet + spi_packet_cur_pos, SPI_DATA_MUX_SIZE);
+
+ switch (spi_data_mux & SPI_DATA_MUX_NORMAL_MASK) {
+ case SPI_DATA_MUX_IPC:
+ queue_info =
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_IPC_RX];
+ tx_div_buf =
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_IPC_RX];
+ break;
+
+ case SPI_DATA_MUX_RAW:
+ queue_info =
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RAW_RX];
+ tx_div_buf =
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RAW_RX];
+ break;
+
+ case SPI_DATA_MUX_RFS:
+ queue_info =
+ &spi_queue_info[SPI_DATA_QUEUE_TYPE_RFS_RX];
+ tx_div_buf =
+ &spi_div_buf[SPI_DATA_QUEUE_TYPE_RFS_RX];
+ break;
+
+ default:
+ SPI_OS_ERROR(("%s len[%u], pos[%u]\n",
+ "[SPI] ERROR : spi_data_parsing_rx_packet : MUX error",
+ spi_packet_length, spi_packet_cur_pos));
+
+ spi_os_trace_dump_low("mux error",
+ spi_packet + spi_packet_cur_pos, 16);
+ return spi_packet_cur_pos - SPI_DATA_PACKET_HEADER_SIZE;
+ }
+
+ /* read spi data length */
+ spi_os_memcpy(&spi_data_length, spi_packet +
+ spi_packet_cur_pos + SPI_DATA_LENGTH_OFFSET,
+ SPI_DATA_LENGTH_SIZE);
+
+ if (spi_data_mux & SPI_DATA_MUX_MORE_H
+ || spi_data_mux & SPI_DATA_MUX_MORE_M)
+ spi_data_length += SPI_DATA_HEADER_SIZE_FRONT;
+ else if (spi_data_mux & SPI_DATA_MUX_MORE_T)
+ spi_data_length += SPI_DATA_HEADER_SIZE;
+ else
+ spi_data_length += SPI_DATA_HEADER_SIZE;
+
+ /* read data and make spi data */
+ spi_cur_data = spi_packet + spi_packet_cur_pos;
+
+ /* verify spi data */
+ if (_spi_data_verify(spi_cur_data, spi_data_mux) == 0) {
+ spi_packet_cur_pos += spi_data_length;
+ continue;
+ }
+
+ /* inqueue rx buffer */
+ if (spi_data_mux & SPI_DATA_MUX_MORE_H
+ || spi_data_mux & SPI_DATA_MUX_MORE_M) {
+ /* middle of divided packet. save to rx_div_buf */
+ spi_os_memcpy((void *)(tx_div_buf->buffer +
+ tx_div_buf->length),
+ spi_cur_data, spi_data_length);
+ tx_div_buf->length +=
+ (spi_data_length - SPI_DATA_HEADER_SIZE_FRONT);
+ } else if (spi_data_mux & SPI_DATA_MUX_MORE_T) {
+ unsigned int spi_origine_len = 0;
+
+ /* tail of divided packet. save to rx_div_buf */
+ spi_os_memcpy((void *)(tx_div_buf->buffer +
+ tx_div_buf->length),
+ spi_cur_data, spi_data_length);
+ tx_div_buf->length += spi_data_length;
+ /* update spi data length at spi header */
+ spi_origine_len =
+ tx_div_buf->length - SPI_DATA_HEADER_SIZE;
+ spi_os_memcpy(tx_div_buf->buffer +
+ SPI_DATA_LENGTH_OFFSET,
+ &(spi_origine_len), SPI_DATA_LENGTH_SIZE);
+
+ /* inqueue from rx_div_buf */
+ spi_data_inqueue(queue_info,
+ tx_div_buf->buffer, tx_div_buf->length);
+
+ spi_os_memset(tx_div_buf->buffer,
+ 0, SPI_DATA_DIVIDE_BUFFER_SIZE);
+ tx_div_buf->length = 0;
+ } else {
+ /* normal packet */
+ spi_data_inqueue(queue_info,
+ spi_cur_data, spi_data_length);
+ }
+
+ /* move spi packet current posision */
+ spi_packet_cur_pos += spi_data_length;
+ } while ((spi_packet_length - 1) > spi_packet_cur_pos);
+
+ return 1;
+}
+
+
+/**********************************************************
+
+Prototype int _spi_data_verify( void * buf, unsigned int mux )
+
+Type function
+
+Description verify integrity of packet
+
+Param input buf : address of packet data received
+
+ mux : data selection
+
+Return value 0 : fail
+
+ 1 : success
+
+***********************************************************/
+
+int _spi_data_verify(void *buf, unsigned int mux)
+{
+ unsigned int length = 0;
+
+ unsigned int max_data_len = SPI_DATA_MAX_SIZE_PER_PACKET;
+ char bof = 0x00;
+ char eof = 0x00;
+
+ spi_os_memcpy(&length, (char *)buf+SPI_DATA_LENGTH_OFFSET,
+ SPI_DATA_LENGTH_SIZE);
+ spi_os_memcpy(&bof, (char *)buf+SPI_DATA_BOF_OFFSET, SPI_DATA_BOF_SIZE);
+
+ if (mux & SPI_DATA_MUX_MORE_H || mux & SPI_DATA_MUX_MORE_M)
+ max_data_len += SPI_DATA_EOF_SIZE;
+
+ if (bof == SPI_DATA_BOF) {
+ if (length <= max_data_len) {
+ if (mux & SPI_DATA_MUX_MORE_H
+ || mux & SPI_DATA_MUX_MORE_M)
+ return 1;
+ else {
+ spi_os_memcpy(&eof,
+ (char *)buf+SPI_DATA_EOF_OFFSET(length),
+ SPI_DATA_EOF_SIZE);
+
+ if (eof != SPI_DATA_EOF) {
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : _spi_data_verify:",
+ "invalid"));
+
+ return 0;
+ }
+ }
+ } else {
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : _spi_data_verify:",
+ "invalid : length error"));
+
+ return 0;
+ }
+ } else {
+ SPI_OS_ERROR(("%s %s\n",
+ "[SPI] ERROR : _spi_data_verify:",
+ "invalid : bof error"));
+
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_data.h b/drivers/phone_svn/ipc_spi/spi_data.h
new file mode 100644
index 0000000..ceb23c8
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_data.h
@@ -0,0 +1,129 @@
+#ifndef _SPI_DATA_H_
+#define _SPI_DATA_H_
+
+#include "spi_dev.h"
+
+#define SPI_TASK_EVENT_COUNT 64
+#define SPI_DATA_BOF 0x7F
+#define SPI_DATA_EOF 0x7E
+#define SPI_DATA_FF_PADDING_HEADER 0xFFFFFFFF
+
+#define SPI_DATA_MUX_NORMAL_MASK 0x0F
+#define SPI_DATA_MUX_MORE_H 0x10
+#define SPI_DATA_MUX_MORE_M 0x20
+#define SPI_DATA_MUX_MORE_T 0x30
+
+#define SPI_DATA_MUX_SIZE 2
+#define SPI_DATA_LENGTH_SIZE 4
+#define SPI_DATA_BOF_SIZE 1
+#define SPI_DATA_INNER_LENGTH_SIZE 4
+#define SPI_DATA_IPC_INNER_LENGTH_SIZE 2
+#define SPI_DATA_IPC_INNER_CONTROL_SIZE 1
+#define SPI_DATA_EOF_SIZE 1
+#define SPI_DATA_HEADER_SIZE (SPI_DATA_MUX_SIZE+ \
+ SPI_DATA_LENGTH_SIZE+SPI_DATA_BOF_SIZE+SPI_DATA_EOF_SIZE)
+#define SPI_DATA_HEADER_SIZE_FRONT (SPI_DATA_MUX_SIZE+ \
+ SPI_DATA_LENGTH_SIZE+SPI_DATA_BOF_SIZE)
+#define SPI_DATA_IPC_INNER_HEADER_SIZE \
+ (SPI_DATA_IPC_INNER_LENGTH_SIZE+ \
+ SPI_DATA_IPC_INNER_CONTROL_SIZE)
+#define SPI_DATA_SIZE(X) (SPI_DATA_HEADER_SIZE+X)
+
+#define SPI_DATA_LENGTH_OFFSET SPI_DATA_MUX_SIZE
+#define SPI_DATA_BOF_OFFSET (SPI_DATA_LENGTH_OFFSET+ \
+ SPI_DATA_LENGTH_SIZE)
+#define SPI_DATA_DATA_OFFSET (SPI_DATA_BOF_OFFSET+ \
+ SPI_DATA_BOF_SIZE)
+#define SPI_DATA_EOF_OFFSET(X) (SPI_DATA_DATA_OFFSET+X)
+
+#define SPI_DATA_PACKET_HEADER_SIZE 4
+#define SPI_DATA_PACKET_MUX_ERROR_SPARE_SIZE 4
+#define SPI_DATA_PACKET_MAX_PACKET_BODY_SIZE \
+ (SPI_DEV_MAX_PACKET_SIZE-SPI_DATA_PACKET_HEADER_SIZE- \
+ SPI_DATA_PACKET_MUX_ERROR_SPARE_SIZE)
+
+#define SPI_DATA_MIN_SIZE (SPI_DATA_HEADER_SIZE*2)
+#define SPI_DATA_MAX_SIZE_PER_PACKET (SPI_DEV_MAX_PACKET_SIZE- \
+ SPI_DATA_PACKET_HEADER_SIZE-SPI_DATA_HEADER_SIZE- \
+ SPI_DATA_PACKET_MUX_ERROR_SPARE_SIZE)
+#define SPI_DATA_MAX_COUNT_PER_PACKET 240
+
+#define SPI_DATA_IPC_QUEUE_SIZE 0x10000
+#define SPI_DATA_RAW_QUEUE_SIZE 0x100000
+#define SPI_DATA_RFS_QUEUE_SIZE 0x100000
+
+#define SPI_DATA_IPC_DIV_BUFFER_SIZE 0x1000
+#define SPI_DATA_RAW_DIV_BUFFER_SIZE 0x1000
+#define SPI_DATA_RFS_DIV_BUFFER_SIZE 0x1000
+
+#define SPI_DATA_DIVIDE_BUFFER_SIZE SPI_DEV_MAX_PACKET_SIZE
+
+
+
+enum SPI_DATA_TYPE_T {
+ SPI_DATA_MUX_IPC = 0x01,
+ SPI_DATA_MUX_RAW = 0x02,
+ SPI_DATA_MUX_RFS = 0x03,
+ SPI_DATA_MUX_CMD = 0x04,
+};
+
+struct spi_data_packet_header {
+ /* 12bit : packet size less than SPI_DEV_PACKET_SIZE */
+ unsigned long current_data_size:31;
+ /* 1bit : packet division flag */
+ unsigned long more:1;
+};
+
+enum SPI_DATA_QUEUE_TYPE_T {
+ SPI_DATA_QUEUE_TYPE_IPC_TX, /* 0 : formatted(IPC) tx buffer */
+ SPI_DATA_QUEUE_TYPE_IPC_RX, /* 1 : formatted(IPC) rx buffer */
+ SPI_DATA_QUEUE_TYPE_RAW_TX, /* 2 : raw tx buffer */
+ SPI_DATA_QUEUE_TYPE_RAW_RX, /* 3 : raw rx buffer */
+ SPI_DATA_QUEUE_TYPE_RFS_TX, /* 4 : rfs tx buffer */
+ SPI_DATA_QUEUE_TYPE_RFS_RX, /* 5 : rfs rx buffer */
+ SPI_DATA_QUEUE_TYPE_NB /* 6 : number of buffer */
+};
+
+struct spi_data_queue {
+ unsigned int tail; /* circular queue header */
+ unsigned int head; /* circular queue tail */
+};
+
+struct spi_data_queue_info {
+ struct spi_data_queue *header;
+ enum SPI_DATA_TYPE_T type;
+ unsigned int buf_size; /* queue size */
+ char *buffer; /* queue data */
+};
+
+struct spi_data_div_buf {
+ unsigned int length;
+ char *buffer; /* queue data */
+};
+
+extern void *ipc_spi_get_queue_buff(void);
+
+extern struct spi_data_queue *spi_data_queue;
+extern struct spi_data_queue_info *spi_queue_info;
+extern char *gspi_data_packet_buf;
+extern char *gspi_data_sync_buf;
+
+extern void spi_data_queue_init(void);
+extern void spi_data_queue_destroy(void);
+extern unsigned int spi_data_dequeue(struct spi_data_queue_info *queue_info,
+ void *pdata);
+extern int spi_data_inqueue(struct spi_data_queue_info *queue, void *data,
+ unsigned int length);
+extern void spi_data_msg_inqueuefront(enum SPI_MAIN_MSG_T task_msg);
+extern int spi_data_queue_is_empty(enum SPI_DATA_QUEUE_TYPE_T type);
+extern int spi_data_div_buf_is_empty(enum SPI_DATA_QUEUE_TYPE_T type);
+extern int spi_data_check_tx_queue(void);
+
+extern int spi_data_prepare_tx_packet(void *buf);
+extern int spi_data_parsing_rx_packet(void *buf, unsigned int length);
+
+extern void spi_data_print_raw_data(void *data, unsigned int length);
+#endif
+
+
+
diff --git a/drivers/phone_svn/ipc_spi/spi_dev.c b/drivers/phone_svn/ipc_spi/spi_dev.c
new file mode 100644
index 0000000..54746d9
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_dev.c
@@ -0,0 +1,345 @@
+/**************************************************************
+
+ spi_dev.c
+
+ adapt device api and spi api
+
+ This is MASTER side.
+
+***************************************************************/
+
+
+
+/**************************************************************
+
+ Preprocessor by common
+
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_dev.h"
+#include "spi_os.h"
+
+
+
+/**************************************************************
+
+ Preprocessor by platform
+ (OMAP4430 && MSM7X30)
+
+***************************************************************/
+
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/phone_svn/ipc_spi.h>
+
+
+
+/**************************************************************
+
+ Definition of Variables and Functions by common
+
+***************************************************************/
+
+int spi_dev_gpio_mrdy;
+int spi_dev_gpio_srdy;
+int spi_dev_gpio_submrdy;
+int spi_dev_gpio_subsrdy;
+
+
+
+/**************************************************************
+
+ Preprocessor by platform
+ (OMAP4430 && MSM7X30)
+
+***************************************************************/
+
+int spi_is_restart;
+
+
+
+/**********************************************************
+
+Prototype void spi_dev_init ( void * data)
+
+Type function
+
+Description init spi gpio info
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+void spi_dev_init(void *data)
+{
+ struct ipc_spi_platform_data *pdata = NULL;
+
+
+ SPI_OS_TRACE(("[SPI] spi_dev_init\n"));
+
+
+ pdata = (struct ipc_spi_platform_data *)data;
+
+ spi_dev_gpio_mrdy = (int) pdata->gpio_ipc_mrdy;
+ spi_dev_gpio_srdy = (int) pdata->gpio_ipc_srdy;
+ spi_dev_gpio_submrdy = (int) pdata->gpio_ipc_sub_mrdy;
+ spi_dev_gpio_subsrdy = (int) pdata->gpio_ipc_sub_srdy;
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_LOW);
+ if (spi_is_restart == 0)
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+}
+
+
+/**********************************************************
+
+Prototype void spi_dev_destroy( void )
+
+Type function
+
+Description unregister irq handler
+
+Param input (none)
+
+Return value (none)
+
+***********************************************************/
+
+void spi_dev_destroy(void)
+{
+ spi_dev_unreigster_irq_handler(spi_dev_gpio_srdy, 0);
+ spi_dev_unreigster_irq_handler(spi_dev_gpio_subsrdy, 0);
+}
+
+
+
+/**********************************************************
+
+Prototype int spi_dev_send
+
+Type function
+
+Description starting data send by DMA(CP side)
+ starting send clock for data switching(AP side)
+
+Param input buf : data for send
+ length : data size. this lengt must be fixed
+
+Return value 0 : success
+ (others) : error cause
+
+***********************************************************/
+
+int spi_dev_send(void *buf, void *sync_buf, unsigned int length)
+{
+ int result = 0;
+
+ result = ipc_spi_tx_rx_sync(buf, sync_buf, length);
+
+ return result;
+}
+
+
+/**********************************************************
+
+Prototype int spi_dev_receive
+
+Type function
+
+Description starting data receive by DMA(CP side)
+ starting send clock for data switching(AP side)
+
+Param input buf : buffer for saving data
+ length : data size. this lengt must be fixed
+
+Return value 0 : success
+ (others) : error cause
+
+***********************************************************/
+
+int spi_dev_receive(void *sync_buf, void *buf, unsigned int length)
+{
+ int value = 0;
+
+ value = ipc_spi_tx_rx_sync(sync_buf, buf, length);
+
+ return value;
+}
+
+
+/**********************************************************
+
+Prototype void spi_dev_set_gpio
+
+Type function
+
+Description set gpio pin state
+
+Param input gpio_id : number of gpio id
+ value : SPI_DEV_GPIOLEVEL_HIGH for raising pin state up
+ : SPI_DEV_GPIOLEVEL_LOW for getting pin state down
+
+Return value (none)
+
+***********************************************************/
+void spi_dev_set_gpio(int gpio_id, enum SPI_DEV_GPIOLEVEL_T value)
+{
+ int level = 0;
+
+ SPI_OS_TRACE_MID(("%s gpio_id =[%d], value =[%d]\n",
+ "[SPI] spi_dev_set_gpio :", gpio_id, (int) value));
+
+ switch (value) {
+ case SPI_DEV_GPIOLEVEL_LOW:
+ level = 0;
+ break;
+ case SPI_DEV_GPIOLEVEL_HIGH:
+ level = 1;
+ break;
+ }
+
+ gpio_set_value((unsigned int) gpio_id, level);
+}
+
+
+
+/**********************************************************
+
+Prototype SPI_DEV_GPIOLEVEL_T spi_dev_get_gpio(int gpio_id)
+
+Type function
+
+Description get gpio pin state
+
+Param input gpio_id : number of gpio id
+
+Return value SPI_DEV_GPIOLEVEL
+
+***********************************************************/
+enum SPI_DEV_GPIOLEVEL_T spi_dev_get_gpio(int gpio_id)
+{
+ enum SPI_DEV_GPIOLEVEL_T value = SPI_DEV_GPIOLEVEL_LOW;
+ int level = 0;
+
+ level = gpio_get_value((unsigned int) gpio_id);
+
+ switch (level) {
+ case 0:
+ value = SPI_DEV_GPIOLEVEL_LOW;
+ break;
+ case 1:
+ value = SPI_DEV_GPIOLEVEL_HIGH;
+ break;
+ }
+
+ return value;
+}
+
+
+/**********************************************************
+
+Prototype int spi_dev_reigster_irq_handler
+
+Type function
+
+Description regist irq callback function to each gpio interrupt
+
+Param input gpio_id : gpio pin id
+ tigger : interrupt detection mode
+ handler : interrupt handler function
+ name : register name
+
+Return value 0 : fail
+ 1 : success
+
+***********************************************************/
+int spi_dev_reigster_irq_handler(int gpio_id,
+ enum SPI_DEV_IRQ_TRIGGER_T trigger,
+ SPI_DEV_IRQ_HANDLER_T handler,
+ char *name, void *data)
+{
+#if defined(SPI_FEATURE_OMAP4430)
+ int value = 0;
+ int _trigger = IRQF_TRIGGER_NONE;
+
+ switch (trigger) {
+ case SPI_DEV_IRQ_TRIGGER_RISING:
+ _trigger = IRQF_TRIGGER_RISING;
+ break;
+ case SPI_DEV_IRQ_TRIGGER_FALLING:
+ _trigger = IRQF_TRIGGER_FALLING;
+ break;
+ default:
+ _trigger = IRQF_TRIGGER_NONE;
+ break;
+ }
+
+ value = request_irq(OMAP_GPIO_IRQ(gpio_id), handler,
+ _trigger, name, data);
+
+ if (value != 0) {
+ SPI_OS_ERROR(("%s regist fail(%d)",
+ "[SPI] ERROR : spi_dev_reigster_irq_handler :",
+ value));
+ return 0;
+ }
+
+#elif defined(SPI_FEATURE_S5PC210)
+ int value = 0;
+
+ int _trigger = IRQF_TRIGGER_NONE;
+ int irq = 0;
+
+
+ switch (trigger) {
+ case SPI_DEV_IRQ_TRIGGER_RISING:
+ _trigger = IRQF_TRIGGER_RISING;
+ break;
+ case SPI_DEV_IRQ_TRIGGER_FALLING:
+ _trigger = IRQF_TRIGGER_FALLING;
+ break;
+ default:
+ _trigger = IRQF_TRIGGER_NONE;
+ break;
+ }
+
+ irq = gpio_to_irq(gpio_id);
+ value = request_irq(irq, handler, _trigger, name, data);
+ if (value != 0) {
+ SPI_OS_ERROR(("spi_dev_reigster_irq_handler: regist fail(%d)",
+ value));
+ return 0;
+ }
+ enable_irq_wake(irq);
+#endif
+
+ return 1;
+}
+
+
+/**********************************************************
+
+void spi_dev_unreigster_irq_handler (int gpio_id, void * data)
+
+Type function
+
+Description unregister irq hanger by gpio api
+
+Param input gpio_id : gpio pin id
+ data : param
+
+Return value (none)
+
+***********************************************************/
+
+void spi_dev_unreigster_irq_handler(int gpio_id, void *data)
+{
+#if defined(SPI_FEATURE_OMAP4430)
+ free_irq(OMAP_GPIO_IRQ(gpio_id), data);
+#elif defined(SPI_FEATURE_S5PC210)
+ free_irq(gpio_to_irq(gpio_id), data);
+#endif
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_dev.h b/drivers/phone_svn/ipc_spi/spi_dev.h
new file mode 100644
index 0000000..6da9e64
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_dev.h
@@ -0,0 +1,49 @@
+#ifndef _SPI_DEV_H_
+#define _SPI_DEV_H_
+
+#include "spi_main.h"
+
+#include <linux/interrupt.h>
+
+#define SPI_DEV_MAX_PACKET_SIZE (2048 * 6)
+
+enum SPI_DEV_SYNC_STATE_T {
+ SPI_DEV_SYNC_OFF = 0,
+ SPI_DEV_SYNC_ON
+};
+
+enum SPI_DEV_GPIOLEVEL_T {
+ SPI_DEV_GPIOLEVEL_LOW = 0,
+ SPI_DEV_GPIOLEVEL_HIGH
+};
+
+enum SPI_DEV_IRQ_TRIGGER_T {
+ SPI_DEV_IRQ_TRIGGER_RISING = 1,
+ SPI_DEV_IRQ_TRIGGER_FALLING
+};
+
+typedef irqreturn_t (*SPI_DEV_IRQ_HANDLER_T)(int, void *);
+#define SPI_DEV_IRQ_HANDLER(X) irqreturn_t X(int irq, void *data)
+
+extern int spi_dev_gpio_mrdy;
+extern int spi_dev_gpio_srdy;
+extern int spi_dev_gpio_submrdy;
+extern int spi_dev_gpio_subsrdy;
+
+extern int spi_is_restart;
+
+extern void spi_dev_init(void *data);
+extern void spi_dev_destroy(void);
+extern int spi_dev_send(void *buf, void * sync_buf, unsigned int length);
+extern int spi_dev_receive(void *sync_buf, void *buf, unsigned int length);
+extern void spi_dev_set_gpio(int gpio_id, enum SPI_DEV_GPIOLEVEL_T value);
+extern enum SPI_DEV_GPIOLEVEL_T spi_dev_get_gpio(int gpio_id);
+extern int spi_dev_reigster_irq_handler(int gpio_id,
+ enum SPI_DEV_IRQ_TRIGGER_T trigger,
+ SPI_DEV_IRQ_HANDLER_T handler,
+ char *name, void *data);
+extern void spi_dev_unreigster_irq_handler(int gpio_id, void *data);
+
+extern int ipc_spi_tx_rx_sync(u8 *tx_d, u8 *rx_d, unsigned len);
+
+#endif
diff --git a/drivers/phone_svn/ipc_spi/spi_main.c b/drivers/phone_svn/ipc_spi/spi_main.c
new file mode 100644
index 0000000..6b104fa
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_main.c
@@ -0,0 +1,563 @@
+/**************************************************************
+ spi_main.c
+
+ process of spi
+
+ This is MASTER side.
+***************************************************************/
+
+/**************************************************************
+ Preprocessor by common
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_os.h"
+#include "spi_dev.h"
+#include "spi_app.h"
+#include "spi_data.h"
+#include "spi_test.h"
+
+/**************************************************************
+ Preprocessor by platform
+ (OMAP4430 && MSM7X30)
+***************************************************************/
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+#include <linux/semaphore.h>
+static struct wake_lock spi_wakelock;
+
+/**************************************************************
+ Definition of Variables and Functions by common
+***************************************************************/
+enum SPI_MAIN_STATE_T spi_main_state = SPI_MAIN_STATE_END;
+
+
+
+static int _start_data_send(void);
+
+static void _start_packet_tx(void);
+
+static void _start_packet_tx_send(void);
+
+static void _start_packet_receive(void);
+
+
+
+
+/**************************************************************
+ Definition of Variables and Functions by platform
+***************************************************************/
+
+#define MRDY_GUARANTEE_MRDY_TIME_GAP 0 /* under 1ms */
+
+#define MRDY_GUARANTEE_MRDY_TIME_SLEEP 2
+
+#define MRDY_GUARANTEE_MRDY_LOOP_COUNT 10000 /* 120us */
+
+
+static void spi_main_process(struct work_struct *pspi_wq);
+
+
+
+#ifdef SPI_GUARANTEE_MRDY_GAP
+
+unsigned long mrdy_low_time_save, mrdy_high_time_save;
+
+int check_mrdy_time_gap(unsigned long x, unsigned long y)
+{
+ if (x == y)
+ return 1;
+ else if ((x < y) && ((y-x) <= MRDY_GUARANTEE_MRDY_TIME_GAP))
+ return 1;
+ else if ((x > y))
+ return 1;
+ else
+ return 0;
+}
+#endif
+
+
+/*=====================================
+* Description set state of spi
+ (Common)
+=====================================*/
+void spi_main_set_state(enum SPI_MAIN_STATE_T state)
+{
+ spi_main_state = state;
+ SPI_OS_TRACE_MID(("[SPI] spi_main_set_state %d=>%d\n",
+ (int)spi_main_state, (int)state));
+}
+
+
+/*=====================================
+* Description an interrupt handler for mrdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_mrdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ return result;
+}
+
+
+/*=====================================
+//Description an interrupt handler for srdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_srdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ if (!boot_done)
+ return result;
+
+ if (!wake_lock_active(&spi_wakelock)) {
+ wake_lock(&spi_wakelock);
+ SPI_OS_TRACE_MID(("[SPI] [%s](%d) spi_wakelock locked .\n",
+ __func__, __LINE__));
+ }
+
+ if (send_modem_spi == 1)
+ up(&srdy_sem); /* signal srdy event */
+
+ /* SRDY interrupt work on SPI_MAIN_STATE_IDLE state for receive data */
+ if (spi_main_state == SPI_MAIN_STATE_IDLE
+ || spi_main_state == SPI_MAIN_STATE_RX_TERMINATE
+ || spi_main_state == SPI_MAIN_STATE_TX_TERMINATE) {
+ spi_main_send_signalfront(SPI_MAIN_MSG_RECEIVE);
+ return result;
+ }
+
+ return result;
+}
+
+
+/*=====================================
+* Description an interrupt handler for submrdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_submrdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ return result;
+}
+
+
+/*=====================================
+* Description an interrupt handler for subsrdy rising
+=====================================*/
+SPI_DEV_IRQ_HANDLER(spi_main_subsrdy_rising_handler)
+{
+ irqreturn_t result = IRQ_HANDLED;
+
+ /* SRDY interrupt work on SPI_MAIN_STATE_TX_WAIT state for send data */
+ if (spi_main_state == SPI_MAIN_STATE_TX_WAIT)
+ return result;
+
+ SPI_OS_TRACE_MID(("%s spi_main_state[%d]\n",
+ "[SPI] spi_main_subsrdy_rising_handler :",
+ (int)spi_main_state));
+
+ return result;
+}
+
+
+/*=====================================
+* Description Send the signal to SPI Task
+=====================================*/
+void spi_main_send_signal(enum SPI_MAIN_MSG_T spi_sigs)
+{
+ struct spi_work *spi_wq = NULL;
+ spi_wq = spi_os_malloc(sizeof(struct spi_work));
+ spi_wq->signal_code = spi_sigs;
+ INIT_WORK(&spi_wq->work, spi_main_process);
+ queue_work(ipc_spi_wq, (struct work_struct *)spi_wq);
+}
+
+
+/*=====================================
+* Description Send the signal to SPI Task
+=====================================*/
+void spi_main_send_signalfront(enum SPI_MAIN_MSG_T spi_sigs)
+{
+ struct spi_work *spi_wq = NULL;
+ spi_wq = spi_os_malloc(sizeof(struct spi_work));
+ spi_wq->signal_code = spi_sigs;
+ INIT_WORK(&spi_wq->work, spi_main_process);
+ queue_work_front(ipc_spi_wq, (struct work_struct *)spi_wq);
+}
+
+
+/*=====================================
+* Description check each queue data and start send routine
+=====================================*/
+static int _start_data_send(void)
+{
+ if (spi_data_check_tx_queue() == 1) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*=====================================
+* Description start to send packet data
+=====================================*/
+static void _start_packet_tx(void)
+{
+ int i = 0;
+
+ if (spi_data_check_tx_queue() == 0)
+ return;
+
+
+ /* check SUB SRDY state */
+ if (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_HIGH) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return;
+ }
+
+ /* check SRDY state */
+ if (spi_dev_get_gpio(spi_dev_gpio_srdy) ==
+ SPI_DEV_GPIOLEVEL_HIGH) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return;
+ }
+
+ if (get_console_suspended()) {
+ spi_main_send_signal(SPI_MAIN_MSG_SEND);
+ return;
+ }
+
+ /* change state SPI_MAIN_STATE_IDLE to SPI_MAIN_STATE_TX_WAIT */
+ spi_main_state = SPI_MAIN_STATE_TX_WAIT;
+
+#ifdef SPI_GUARANTEE_MRDY_GAP
+ mrdy_high_time_save = spi_os_get_tick();
+ if (check_mrdy_time_gap(mrdy_low_time_save, mrdy_high_time_save))
+ spi_os_sleep(1);
+#endif
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ /* check SUBSRDY state */
+ while (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW) {
+ if (i == 0) {
+ spi_os_sleep(1);
+ i++;
+ continue;
+ } else
+ spi_os_sleep(MRDY_GUARANTEE_MRDY_TIME_SLEEP);
+
+ i++;
+ if (i > MRDY_GUARANTEE_MRDY_TIME_SLEEP * 20) {
+ SPI_OS_ERROR(("%s spi_main_state=[%d]\n",
+ "[SPI] === spi Fail to receiving SUBSRDY CONF :",
+ (int)spi_main_state));
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy,
+ SPI_DEV_GPIOLEVEL_LOW);
+#ifdef SPI_GUARANTEE_MRDY_GAP
+ mrdy_low_time_save = spi_os_get_tick();
+#endif
+ /* change state SPI_MAIN_STATE_TX_WAIT */
+ /* to SPI_MAIN_STATE_IDLE */
+ if (spi_main_state != SPI_MAIN_STATE_START
+ && spi_main_state != SPI_MAIN_STATE_END
+ && spi_main_state != SPI_MAIN_STATE_INIT) {
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ _start_data_send();
+ }
+ return;
+ }
+ }
+ if (spi_main_state != SPI_MAIN_STATE_START
+ && spi_main_state != SPI_MAIN_STATE_END
+ && spi_main_state != SPI_MAIN_STATE_INIT) {
+ _start_packet_tx_send();
+ } else
+ SPI_OS_ERROR(("[SPI] ERR : _start_packet_tx:spi_main_state[%d]",
+ (int)spi_main_state));
+
+ return;
+}
+
+
+/*=====================================
+* Description send data
+=====================================*/
+static void _start_packet_tx_send(void)
+{
+ char *spi_packet_buf = NULL;
+ char *spi_sync_buf = NULL;
+
+ /* change state SPI_MAIN_STATE_TX_WAIT to SPI_MAIN_STATE_TX_SENDING */
+ spi_main_state = SPI_MAIN_STATE_TX_SENDING;
+
+ spi_packet_buf = gspi_data_packet_buf;
+ spi_sync_buf = gspi_data_sync_buf;
+
+ spi_os_memset(spi_packet_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+ spi_os_memset(spi_sync_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+
+ spi_data_prepare_tx_packet(spi_packet_buf);
+ if (spi_dev_send((void *)spi_packet_buf, (void *)spi_sync_buf,
+ SPI_DEV_MAX_PACKET_SIZE) != 0) {
+ /* TODO: save failed packet */
+ /* back data to each queue */
+ SPI_OS_ERROR(("[SPI] spi_dev_send fail\n"));
+ panic("[SPI] spi_dev_send\n");
+ }
+
+ spi_main_state = SPI_MAIN_STATE_TX_TERMINATE;
+
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_LOW);
+#ifdef SPI_GUARANTEE_MRDY_GAP
+ mrdy_low_time_save = spi_os_get_tick();
+#endif
+
+ /* change state SPI_MAIN_STATE_TX_SENDING to SPI_MAIN_STATE_IDLE */
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ _start_data_send();
+}
+
+
+/*=====================================
+* Description start to receive packet data
+=====================================*/
+static void _start_packet_receive(void)
+{
+ char *spi_packet_buf = NULL;
+ char *spi_sync_buf = NULL;
+ struct spi_data_packet_header spi_receive_packet_header = {0, };
+ int i = 0;
+
+ if (!wake_lock_active(&spi_wakelock))
+ return;
+
+ if (spi_dev_get_gpio(spi_dev_gpio_srdy) == SPI_DEV_GPIOLEVEL_LOW)
+ return;
+
+ if (get_console_suspended())
+ return;
+
+ spi_main_state = SPI_MAIN_STATE_RX_WAIT;
+
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+
+ /* check SUBSRDY state */
+ while (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW) {
+ if (i == 0) {
+ spi_os_sleep(1);
+ i++;
+ continue;
+ } else
+ spi_os_sleep(MRDY_GUARANTEE_MRDY_TIME_SLEEP);
+
+ i++;
+ if (i > MRDY_GUARANTEE_MRDY_TIME_SLEEP * 20) {
+ SPI_OS_ERROR(("[SPI] ERROR(Failed MASTER RX:%d/%d)",
+ i, MRDY_GUARANTEE_MRDY_TIME_SLEEP * 20));
+ if (spi_main_state != SPI_MAIN_STATE_START
+ && spi_main_state != SPI_MAIN_STATE_END
+ && spi_main_state != SPI_MAIN_STATE_INIT) {
+ spi_dev_set_gpio(spi_dev_gpio_submrdy,
+ SPI_DEV_GPIOLEVEL_LOW);
+
+ /* change state SPI_MAIN_STATE_RX_WAIT */
+ /* to SPI_MAIN_STATE_IDLE */
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ }
+ return;
+ }
+ }
+
+ if (spi_main_state == SPI_MAIN_STATE_START
+ || spi_main_state == SPI_MAIN_STATE_END
+ || spi_main_state == SPI_MAIN_STATE_INIT)
+ return;
+
+ spi_packet_buf = gspi_data_packet_buf;
+ spi_sync_buf = gspi_data_sync_buf;
+
+ spi_os_memset(spi_packet_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+ spi_os_memset(spi_sync_buf, 0, SPI_DEV_MAX_PACKET_SIZE);
+
+ if (spi_dev_receive((void *)spi_sync_buf, (void *)spi_packet_buf,
+ SPI_DEV_MAX_PACKET_SIZE) == 0) {
+ /* parsing SPI packet */
+ spi_os_memcpy(&spi_receive_packet_header, spi_packet_buf,
+ SPI_DATA_PACKET_HEADER_SIZE);
+
+ if (spi_data_parsing_rx_packet((void *)spi_packet_buf,
+ spi_receive_packet_header.current_data_size) > 0) {
+ /* call function for send data to IPC, RAW, RFS */
+ spi_send_msg_to_app();
+ }
+ } else{
+ SPI_OS_ERROR(("[SPI] spi_dev_receive fail\n"));
+ panic("[SPI] spi_dev_receive\n");
+ }
+
+ spi_main_state = SPI_MAIN_STATE_RX_TERMINATE;
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+
+ /* change state SPI_MAIN_STATE_RX_WAIT to SPI_MAIN_STATE_IDLE */
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ _start_data_send();
+
+ return;
+}
+
+
+/*=====================================
+* Description creating a task
+=====================================*/
+void spi_main_init(void *data)
+{
+ struct ipc_spi_platform_data *pdata;
+
+ SPI_OS_TRACE(("[SPI] spi_main_init\n"));
+
+ spi_main_state = SPI_MAIN_STATE_START;
+
+
+ pdata = (struct ipc_spi_platform_data *)data;
+
+ wake_lock_init(&spi_wakelock, WAKE_LOCK_SUSPEND,
+ "samsung-spiwakelock");
+
+ spi_dev_init(pdata);
+
+ spi_dev_reigster_irq_handler (spi_dev_gpio_srdy,
+ SPI_DEV_IRQ_TRIGGER_RISING,
+ spi_main_srdy_rising_handler,
+ "spi_srdy_rising", 0);
+ spi_dev_reigster_irq_handler (spi_dev_gpio_subsrdy,
+ SPI_DEV_IRQ_TRIGGER_RISING,
+ spi_main_subsrdy_rising_handler,
+ "spi_subsrdy_rising", 0);
+}
+
+
+/*=====================================
+* Description main process
+=====================================*/
+
+static void spi_main_process(struct work_struct *work)
+{
+ int signal_code;
+
+ struct spi_work *spi_wq = container_of(work, struct spi_work, work);
+ signal_code = spi_wq->signal_code;
+
+
+ if (spi_main_state == SPI_MAIN_STATE_END
+ || spi_main_state == SPI_MAIN_STATE_START) {
+ spi_os_free(spi_wq);
+ return;
+ }
+
+ switch (signal_code) {
+ case SPI_MAIN_MSG_SEND:
+ if (spi_main_state == SPI_MAIN_STATE_IDLE)
+ _start_packet_tx();
+
+ break;
+
+ case SPI_MAIN_MSG_PACKET_SEND:
+ _start_packet_tx_send();
+ break;
+
+ case SPI_MAIN_MSG_RECEIVE:
+ if (spi_main_state == SPI_MAIN_STATE_IDLE
+ || spi_main_state == SPI_MAIN_STATE_RX_TERMINATE
+ || spi_main_state == SPI_MAIN_STATE_TX_TERMINATE)
+ _start_packet_receive();
+ break;
+
+ /* Receive data from IPC,RAW,RFS. */
+ /* It need analyze and save to tx queue */
+ case SPI_MAIN_MSG_IPC_SEND:
+ case SPI_MAIN_MSG_RAW_SEND:
+ case SPI_MAIN_MSG_RFS_SEND:
+ /* start send data during SPI_MAIN_STATE_IDLE state */
+ if (spi_main_state == SPI_MAIN_STATE_IDLE)
+ _start_data_send();
+ break;
+
+ default:
+ SPI_OS_ERROR(("[SPI] ERROR(No signal_code in spi_main[%d])\n",
+ signal_code));
+ break;
+ }
+
+ spi_os_free(spi_wq);
+ if (wake_lock_active(&spi_wakelock)) {
+ wake_unlock(&spi_wakelock);
+ SPI_OS_TRACE_MID(("[SPI] [%s](%d) spi_wakelock unlocked .\n",
+ __func__, __LINE__));
+ }
+}
+
+
+/*=====================================
+//Description main task
+=====================================*/
+void spi_main(unsigned long argc, void *argv)
+{
+ /* queue init */
+ spi_data_queue_init();
+
+ SPI_OS_TRACE(("[SPI] spi_main %x\n", (unsigned int)argv));
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ do {
+ spi_os_sleep(30);
+ } while (spi_dev_get_gpio(spi_dev_gpio_subsrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW);
+
+ if (spi_is_restart)
+ spi_os_sleep(100);
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_main_state = SPI_MAIN_STATE_IDLE;
+ spi_is_restart = 0;
+}
+
+
+/*=====================================
+* Description spi restart for CP slient reset
+=====================================*/
+
+void spi_set_restart(void)
+{
+ SPI_OS_ERROR(("[SPI] spi_set_restart(spi_main_state=[%d])\n",
+ (int)spi_main_state));
+
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+
+ spi_main_state = SPI_MAIN_STATE_END;
+
+ spi_is_restart = 1;
+
+ flush_workqueue(ipc_spi_wq);
+
+ spi_data_queue_destroy();
+
+ spi_dev_destroy();
+
+ if (wake_lock_active(&spi_wakelock)) {
+ wake_unlock(&spi_wakelock);
+ SPI_OS_TRACE_MID(("[SPI] [%s](%d) spi_wakelock unlocked.\n",
+ __func__, __LINE__));
+ }
+ wake_lock_destroy(&spi_wakelock);
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_main.h b/drivers/phone_svn/ipc_spi/spi_main.h
new file mode 100644
index 0000000..b15465a
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_main.h
@@ -0,0 +1,80 @@
+#ifndef __SPI_MAIN_H__
+#define __SPI_MAIN_H__
+
+#define SPI_FEATURE_S5PC210
+#define SPI_FEATURE_MASTER
+
+#define SPI_FEATURE_NOLOG
+/* #define SPI_FEATURE_DEBUG */
+#define SPI_GUARANTEE_MRDY_GAP
+
+/*
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_MASTER_SENDING
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_SLAVE_SENDING
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_PHYSICAL
+#define SPI_FEATURE_TEST_SCENARIO SPI_TEST_SCENARIO_NONE
+#define SPI_FEATURE_TEST_DURATION 1000
+*/
+
+#define SPI_SLAVE_TX 0
+#define SPI_SLAVE_RX 0
+#define SPI_MASTER_TX 0
+#define SPI_MASTER_RX 0
+
+#include "spi_os.h"
+
+enum SPI_MAIN_MSG_T {
+ SPI_MAIN_MSG_BASE,
+ SPI_MAIN_MSG_SEND,
+ SPI_MAIN_MSG_RECEIVE,
+ SPI_MAIN_MSG_PACKET_SEND,
+ SPI_MAIN_MSG_PACKET_RECEIVE,
+ SPI_MAIN_MSG_IPC_SEND, /* IPC sends message to SPI */
+ SPI_MAIN_MSG_RAW_SEND, /* RAW sends message to SPI */
+ SPI_MAIN_MSG_RFS_SEND /* RFS sends message to SPI */
+};
+
+enum SPI_MAIN_STATE_T {
+ SPI_MAIN_STATE_START, /* before init complete */
+ SPI_MAIN_STATE_INIT, /* initialising */
+ SPI_MAIN_STATE_IDLE, /* suspend. Waiting for event */
+
+ /* state to start tx. Become from idle */
+ SPI_MAIN_STATE_TX_START,
+ SPI_MAIN_STATE_TX_CONFIRM,
+
+ /* (in case of master) */
+ /* wait srdy rising interrupt to check slave preparing */
+ /* (in case of slave) */
+ /* wait submrdy rising interrupt to check sync complete */
+ SPI_MAIN_STATE_TX_WAIT,
+ SPI_MAIN_STATE_TX_SENDING, /* tx data sending */
+ SPI_MAIN_STATE_TX_TERMINATE,
+ SPI_MAIN_STATE_TX_MORE,
+
+ /* in case of slave, wait submrdy rising interrupt to */
+ SPI_MAIN_STATE_RX_WAIT,
+
+ /* check sync complete then it starts to read buffer */
+ SPI_MAIN_STATE_RX_MORE,
+ SPI_MAIN_STATE_RX_TERMINATE,
+ SPI_MAIN_STATE_END /* spi task is stopped */
+};
+
+extern struct workqueue_struct *ipc_spi_wq;
+extern int send_modem_spi;
+extern int boot_done;
+extern struct semaphore srdy_sem;
+
+
+extern enum SPI_MAIN_STATE_T spi_main_state;
+
+extern void spi_main(unsigned long argc, void *argv);
+extern void spi_main_init(void *data);
+extern void spi_main_send_signal(enum SPI_MAIN_MSG_T spi_sigs);
+extern void spi_main_send_signalfront(enum SPI_MAIN_MSG_T spi_sigs);
+extern void spi_set_restart(void);
+extern int get_console_suspended(void);
+
+#endif
+
diff --git a/drivers/phone_svn/ipc_spi/spi_os.c b/drivers/phone_svn/ipc_spi/spi_os.c
new file mode 100644
index 0000000..f1d2550
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_os.c
@@ -0,0 +1,634 @@
+/**************************************************************
+ spi_os.c
+
+ adapt os api and spi api
+
+ This is MATER side.
+***************************************************************/
+
+/**************************************************************
+ Preprocessor by common
+***************************************************************/
+
+#include "spi_main.h"
+#include "spi_os.h"
+
+
+/**************************************************************
+ Preprocessor by platform
+ (Android)
+***************************************************************/
+
+#include <linux/vmalloc.h>
+#include <linux/spi/spi.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/in.h>
+#include <linux/time.h>
+
+/**********************************************************
+Prototype void * spi_os_malloc ( unsigned int length )
+
+Type function
+
+Description allocate memory
+
+Param input length : length of size
+
+Return value 0 : fail
+ (other) : address of memory allocated
+***********************************************************/
+void *spi_os_malloc(unsigned int length)
+{
+ if (length <= 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_malloc fail : len 0\n"));
+ return 0;
+ }
+
+ return kmalloc(length, GFP_ATOMIC);
+}
+
+
+/*====================================
+Prototype void * spi_os_vmalloc ( unsigned int length )
+
+Type function
+
+Description allocate memory with vmalloc
+
+Param input length : length of size
+
+Return value 0 : fail
+ (other) : address of memory allocated
+====================================*/
+void *spi_os_vmalloc(unsigned int length)
+{
+ if (length <= 0) {
+ SPI_OS_ERROR(("spi_os_malloc fail : length is 0\n"));
+ return 0;
+ }
+ return vmalloc(length);
+}
+
+
+/**********************************************************
+Prototype int spi_os_free ( void * addr )
+
+Type function
+
+Description free memory
+
+Param input addr : address of memory to be released
+
+Return value 0 : fail
+ 1 : success
+***********************************************************/
+int spi_os_free(void *addr)
+{
+ if (addr == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_free fail : addr is 0\n"));
+ return 0;
+ }
+
+ kfree(addr);
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_vfree ( void * addr )
+
+Type function
+
+Description free memory with vfree
+
+Param input addr : address of memory to be released
+
+Return value 0 : fail
+ 1 : success
+***********************************************************/
+int spi_os_vfree(void *addr)
+{
+ if (addr == 0) {
+ SPI_OS_ERROR(("spi_os_free fail : addr is 0\n"));
+ return 0;
+ }
+
+#ifdef SPI_FEATURE_OMAP4430
+ vfree(addr);
+#elif defined SPI_FEATURE_SC8800G
+ SCI_FREE(addr);
+#endif
+
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_memcpy ( void * dest, void * src, unsigned int length )
+
+Type function
+
+Description copy memory
+
+Param input dest : address of memory to be save
+ src : address of memory to copy
+ length : length of memory to copy
+
+Return value 0 : fail
+ 1 : success
+***********************************************************/
+int spi_os_memcpy(void *dest, void *src, unsigned int length)
+{
+ if (dest == 0 || src == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ memcpy(dest, src, length);
+
+ return 1;
+}
+
+
+/**********************************************************
+Prototype void * spi_os_memset ( void * addr, int value, unsigned int length )
+
+Type function
+
+Description set memory as parameter
+
+Param input addr : address of memory to be set
+ value : value to set
+ length : length of memory to be set
+
+Return value (none)
+***********************************************************/
+void *spi_os_memset(void *addr, int value, unsigned int length)
+{
+ if (addr == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ return memset(addr, value, length);
+}
+
+
+/**********************************************************
+Prototype int spi_os_create_mutex( char * name, unsigned int priority_inherit )
+
+Type function
+
+Description create mutex
+
+Param input name : name of mutex
+ priority_inherit : mutex inheritance
+
+Return value id of mutex created
+***********************************************************/
+int spi_os_create_mutex(char *name, unsigned int priority_inherit)
+{
+ if (name == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_delete_mutex ( int pmutex )
+
+Type function
+
+Description delete mutex
+
+Param input pmutex : id of mutex
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_delete_mutex(int pmutex)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_acquire_mutex ( int pmutex, unsigned int wait )
+
+Type function
+
+Description acquire mutex
+
+Param input pmutex : id of mutex to acquire
+ wait : mutex waiting time
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_acquire_mutex(int pmutex, unsigned int wait)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_release_mutex (int pmutex )
+
+Type function
+
+Description release mutex
+
+Param input pmutex : id of mutex to release
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_release_mutex(int pmutex)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_create_sem ( char * name, unsigned int init_count)
+
+Type function
+
+Description create semaphore
+
+Param input name : name of semaphore
+ init_count : semaphore count
+
+Return value id of semaphore created
+***********************************************************/
+int spi_os_create_sem(char *name, unsigned int init_count)
+{
+ if (name == 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_memcpy fail\n"));
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_delete_sem ( int sem )
+
+Type function
+
+Description delete semaphore
+
+Param input sem : id of semaphore to delete
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_delete_sem(int sem)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_acquire_sem (int sem, unsigned int wait )
+
+Type function
+
+Description acquire semaphore
+
+Param input sem : id of semaphore to acquire
+ wait : mutex waiting time
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_acquire_sem(int sem, unsigned int wait)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype int spi_os_release_sem (int sem )
+
+Type function
+
+Description release semaphore
+
+Param input sem : id of semaphore to release
+
+Return value 0 : success
+ 1 : fail
+***********************************************************/
+int spi_os_release_sem(int sem)
+{
+ return 0;
+}
+
+
+/**********************************************************
+Prototype void spi_os_sleep ( unsigned long msec )
+
+Type function
+
+Description sleep os
+
+Param input msec : time to sleep
+
+Return value (none)
+***********************************************************/
+void spi_os_sleep(unsigned long msec)
+{
+ if (msec <= 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_sleep fail\n"));
+ return;
+ }
+
+ msleep(msec);
+}
+
+
+/**********************************************************
+Prototype void spi_os_loop_delay ( unsigned long cnt )
+
+Type function
+
+Description delay task with loop
+
+Param input cnt : delay count
+
+Return value (none)
+***********************************************************/
+void spi_os_loop_delay(unsigned long cnt)
+{
+ unsigned int timeout;
+ timeout = 0;
+ while (++timeout < cnt)
+ ;
+}
+
+
+/**********************************************************
+Prototype void * spi_os_create_timer
+
+Type function
+
+Description create timer
+
+Param input name : timer name
+ callback : timer callback function
+ param : timer param
+ duration : timer expire duration
+
+Return value timer ptr
+***********************************************************/
+int spi_os_create_timer(void *timer, char *name,
+ SPI_OS_TIMER_T callback, int param, unsigned long duration)
+{
+ struct timer_list *tm = timer;
+
+
+ if (name == 0 || callback == 0 || param <= 0 || duration <= 0) {
+ SPI_OS_ERROR(("[SPI] ERROR : spi_os_create_timer fail\n"));
+ return 0;
+ }
+
+ init_timer(tm);
+
+ tm->expires = jiffies + ((duration * HZ) / 1000);
+ tm->data = (unsigned long) param;
+ tm->function = callback;
+
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_start_timer
+
+Type function
+
+Description start timer
+
+Param input timer : timer ptr
+ callback : timer callback function
+ param : timer param
+ duration : timer expire duration
+
+Return value 1 : success
+ 0 : fail
+***********************************************************/
+int spi_os_start_timer(void *timer, SPI_OS_TIMER_T callback,
+ int param, unsigned long duration)
+{
+ add_timer((struct timer_list *) timer);
+ return 1;
+}
+
+
+/**********************************************************
+Prototype int spi_os_stop_timer (void * timer)
+
+Type function
+
+Description stop timer
+
+Param input timer : timer ptr
+
+Return value 1 : success
+ 0 : fail
+***********************************************************/
+int spi_os_stop_timer(void *timer)
+{
+ int value = 0;
+
+ value = del_timer((struct timer_list *) timer);
+
+ return value;
+}
+
+
+/**********************************************************
+Prototype int spi_os_delete_timer (void * timer)
+
+Type function
+
+Description delete timer
+
+Param input timer : timer ptr
+
+Return value 1 : success
+ 0 : fail
+***********************************************************/
+int spi_os_delete_timer(void *timer)
+{
+ return 1;
+}
+
+
+/**********************************************************
+Prototype unsigned long spi_os_get_tick (void)
+
+Type function
+
+Description get system tick
+
+Param input (none)
+
+Return value system tick
+
+***********************************************************/
+unsigned long spi_os_get_tick(void)
+{
+ unsigned long tick = 0;
+
+ tick = jiffies_to_msecs(jiffies);
+ return tick;
+}
+
+
+/**********************************************************
+Prototype void spi_os_get_tick_by_log (char * name)
+
+Type function
+
+Description print tick time to log
+
+Param input name : print name
+
+Return value (none)
+***********************************************************/
+void spi_os_get_tick_by_log(char *name)
+{
+ SPI_OS_TRACE(("[SPI] %s tick %lu ms\n", name, spi_os_get_tick()));
+
+}
+
+
+/**********************************************************
+Prototype void spi_os_trace_dump (char * name, void * data, int length)
+
+Description print buffer value by hex code
+ if buffer size too big, it change to....
+ and print 64 byte of front and 64 byte of tail
+
+Param input name : print name
+ data : buffer for print
+ length : print length
+
+Return value (none)
+***********************************************************/
+void spi_os_trace_dump(char *name, void *data, int length)
+{
+#ifdef SPI_FEATURE_DEBUG
+ #define SPI_OS_TRACE_DUMP_PER_LINE 16
+ #define SPI_OS_TRACE_MAX_LINE 8
+ #define SPI_OS_TRACE_HALF_LINE
+ (SPI_OS_TRACE_MAX_LINE / 2)
+ #define SPI_OS_TRACE_MAX_DUMP_SIZE
+ (SPI_OS_TRACE_DUMP_PER_LINE*SPI_OS_TRACE_MAX_LINE)
+
+ int i = 0, lines = 0, halflinemode = 0;
+
+ char buf[SPI_OS_TRACE_DUMP_PER_LINE * 3 + 1];
+ char *pdata = NULL;
+
+ char ch = 0;
+
+ SPI_OS_TRACE_MID(("[SPI] spi_os_trace_dump (%s length[%d])\n",
+ name, length));
+
+ spi_os_memset(buf, 0x00, sizeof(buf));
+
+ if (length > SPI_OS_TRACE_MAX_DUMP_SIZE)
+ halflinemode = 1;
+
+ pdata = data;
+ for (i = 0 ; i < length ; i++) {
+ if ((i != 0) && ((i % SPI_OS_TRACE_DUMP_PER_LINE) == 0)) {
+ buf[SPI_OS_TRACE_DUMP_PER_LINE*3] = 0;
+ SPI_OS_TRACE_MID(("%s\n", buf));
+ spi_os_memset(buf, 0x00, sizeof(buf));
+ lines++;
+ if (SPI_OS_TRACE_HALF_LINE == lines
+ && halflinemode == 1) {
+ SPI_OS_TRACE_MID((" ......\n"));
+ pdata += (length - SPI_OS_TRACE_MAX_DUMP_SIZE);
+ i += (length - SPI_OS_TRACE_MAX_DUMP_SIZE);
+ }
+ }
+
+ ch = (*pdata&0xF0)>>4;
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ ch = (*pdata&0x0F);
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+1] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+2] = 0x20;
+ pdata++;
+ }
+
+ if (buf[0] != '\0')
+ SPI_OS_TRACE_MID(("%s\n", buf));
+
+ #undef SPI_OS_TRACE_DUMP_PER_LINE
+ #undef SPI_OS_TRACE_MAX_LINE
+ #undef SPI_OS_TRACE_HALF_LINE
+ #undef SPI_OS_TRACE_MAX_DUMP_SIZE
+#endif
+}
+
+
+/**********************************************************
+Prototype void spi_os_trace_dump (char * name, void * data, int length)
+
+Description print buffer value by hex code as SPI_OS_TRACE
+
+ this function print only 16 byte
+
+Param input name : print name
+ data : buffer for print
+ length : print length
+
+Return value (none)
+***********************************************************/
+
+void spi_os_trace_dump_low(char *name, void *data, int length)
+{
+ #define SPI_OS_TRACE_DUMP_PER_LINE 16
+
+ int i = 0;
+ char buf[SPI_OS_TRACE_DUMP_PER_LINE * 3 + 1] = {0,};
+ char *pdata = NULL;
+ char ch = 0;
+
+ SPI_OS_ERROR(("[SPI] spi_os_trace_dump_low (%s length[%d])\n",
+ name, length));
+
+ spi_os_memset(buf, 0x00, sizeof(buf));
+
+ if (length > SPI_OS_TRACE_DUMP_PER_LINE)
+ length = SPI_OS_TRACE_DUMP_PER_LINE;
+
+ pdata = data;
+ for (i = 0 ; i < length ; i++) {
+ ch = (*pdata&0xF0)>>4;
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ ch = (*pdata&0x0F);
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+1] =
+ ((ch > 9) ? (ch-10 + 'A') : (ch + '0'));
+ buf[(i%SPI_OS_TRACE_DUMP_PER_LINE)*3+2] = 0x20;
+ pdata++;
+ }
+
+ if (buf[0] != '\0')
+ SPI_OS_ERROR(("%s\n", buf));
+
+ #undef SPI_OS_TRACE_DUMP_PER_LINE
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_os.h b/drivers/phone_svn/ipc_spi/spi_os.h
new file mode 100644
index 0000000..5174144
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_os.h
@@ -0,0 +1,82 @@
+#ifndef __SPI_OS_H__
+#define __SPI_OS_H__
+
+#include "spi_main.h"
+
+#include <linux/kernel.h>
+#include <linux/workqueue.h>
+
+
+#define SPI_OS_ASSERT(x) printk x
+#define SPI_OS_ERROR(x) printk x
+
+#ifdef SPI_FEATURE_NOLOG
+#define SPI_OS_TRACE_MID(x)
+#define SPI_OS_TRACE(x)
+#else
+#define SPI_OS_TRACE(x) printk x
+#ifdef SPI_FEATURE_DEBUG
+#define SPI_OS_TRACE_MID(x) printk x
+#else
+#define SPI_OS_TRACE_MID(x)
+#endif /* SPI_FEATURE_DEBUG */
+#endif /* SPI_FEATURE_NOLOG */
+
+struct spi_work {
+ struct work_struct work;
+ int signal_code;
+};
+
+struct spi_os_msg {
+ unsigned int signal_code;
+ unsigned int data_length;
+ void *data;
+};
+
+typedef void (*SPI_OS_TIMER_T)(unsigned long);
+/* Inherit option */
+#define SPI_OS_MUTEX_NO_INHERIT 0
+#define SPI_OS_MUTEX_INHERIT 1
+/* Wait option. */
+#define SPI_OS_MUTEX_NO_WAIT /* TBD */
+#define SPI_OS_MUTEX_WAIT_FOREVER /* TBD */
+#define SPI_OS_TIMER_CALLBACK(X) void X(unsigned long param)
+
+/* Memory */
+extern void *spi_os_malloc(unsigned int length);
+extern void *spi_os_vmalloc(unsigned int length);
+extern int spi_os_free(void *addr);
+extern int spi_os_vfree(void *addr);
+extern int spi_os_memcpy(void *dest, void *src, unsigned int length);
+extern void *spi_os_memset(void *addr, int value, unsigned int length);
+
+/* Mutex */
+extern int spi_os_create_mutex(char *name,
+ unsigned int priority_inherit);
+extern int spi_os_delete_mutex(int sem);
+extern int spi_os_acquire_mutex(int sem, unsigned int wait);
+extern int spi_os_release_mutex(int sem);
+
+
+/* Semaphore */
+extern int spi_os_create_sem(char *name, unsigned int init_count);
+extern int spi_os_delete_sem(int sem);
+extern int spi_os_acquire_sem(int sem, unsigned int wait);
+extern int spi_os_release_sem(int sem);
+
+/* Timer */
+extern void spi_os_sleep(unsigned long msec);
+extern void spi_os_loop_delay(unsigned long cnt);
+extern int spi_os_create_timer(void *timer, char *name,
+ SPI_OS_TIMER_T callback, int param, unsigned long duration);
+extern int spi_os_start_timer(void *timer, SPI_OS_TIMER_T callback,
+ int param, unsigned long duration);
+extern int spi_os_stop_timer(void *timer);
+extern int spi_os_delete_timer(void *timer);
+
+/* Log */
+extern unsigned long spi_os_get_tick(void);
+extern void spi_os_get_tick_by_log(char *name);
+extern void spi_os_trace_dump(char *name, void *data, int length);
+extern void spi_os_trace_dump_low(char *name, void *data, int length);
+#endif
diff --git a/drivers/phone_svn/ipc_spi/spi_test.c b/drivers/phone_svn/ipc_spi/spi_test.c
new file mode 100644
index 0000000..31f717f
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_test.c
@@ -0,0 +1,270 @@
+#include "spi_main.h"
+#include "spi_test.h"
+#include "spi_os.h"
+#include "spi_dev.h"
+#include "spi_app.h"
+
+enum SPI_TEST_SCENARIO_T spi_test_scenario_mode = SPI_TEST_SCENARIO_NONE;
+
+static void _scenario_physical(void);
+static void _scenario_sending(int param);
+
+
+static void _scenario_physical(void)
+{
+ int count = 0;
+ int failcount = 0;
+ int i;
+ char txbuf[SPI_DEV_MAX_PACKET_SIZE];
+ char rxbuf[SPI_DEV_MAX_PACKET_SIZE];
+
+ SPI_OS_TRACE_MID(("spi_scenario_physical\n"));
+
+ spi_os_memset(txbuf, 0x00, sizeof(txbuf));
+ for (i = 0 ; i < SPI_DEV_MAX_PACKET_SIZE ; i++)
+ txbuf[i] = i%100;
+
+ while (count < 100) {
+ SPI_OS_TRACE_MID(("spi _scenario_physical %d\n", count));
+ SPI_OS_TRACE_MID(("%s mrdy %d srdy %d submrdy %d subsrdy %d\n",
+ "spi_scenario_physical test start",
+ spi_dev_get_gpio(spi_dev_gpio_mrdy),
+ spi_dev_get_gpio(spi_dev_gpio_srdy),
+ spi_dev_get_gpio(spi_dev_gpio_submrdy),
+ spi_dev_get_gpio(spi_dev_gpio_subsrdy)));
+
+ txbuf[0] = count;
+ spi_os_memset(rxbuf, 0x00, sizeof(rxbuf));
+
+#ifdef SPI_FEATURE_MASTER
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+ SPI_OS_TRACE_MID(("%s, subsrdy high\n",
+ "spi_scenario_physical test wait srdy"));
+ spi_dev_set_gpio(spi_dev_gpio_mrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ while (spi_dev_get_gpio(spi_dev_gpio_srdy) ==
+ SPI_DEV_GPIOLEVEL_LOW)
+ ;
+
+ /* spreadtrum recommend. */
+ /* master should send/receive after that slave is ready. */
+ spi_os_sleep(20);
+
+ if (count % 2 == 0) {
+ spi_dev_send(txbuf, SPI_DEV_MAX_PACKET_SIZE);
+ } else {
+ spi_dev_receive(rxbuf, SPI_DEV_MAX_PACKET_SIZE);
+ for (i = 1 ; i < SPI_DEV_MAX_PACKET_SIZE ; i++) {
+ if (rxbuf[i] != txbuf[i]) {
+ failcount++;
+ spi_os_trace_dump("spi_scenario_physical receiving fail",
+ &rxbuf[i-8], 16);
+ SPI_OS_TRACE_MID(("%s %d count %d/%d\n",
+ "spi_scenario_physical test receiving fail",
+ i, failcount, count));
+ i = sizeof(rxbuf);
+ break;
+ }
+ }
+ }
+
+ spi_os_sleep(20);
+ spi_dev_set_gpio(spi_dev_gpio_submrdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+#elif defined SPI_FEATURE_SLAVE
+ spi_dev_set_gpio(spi_dev_gpio_srdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+ spi_dev_set_gpio(spi_dev_gpio_subsrdy, SPI_DEV_GPIOLEVEL_LOW);
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+ while (spi_dev_get_gpio(spi_dev_gpio_mrdy) ==
+ SPI_DEV_GPIOLEVEL_LOW)
+ ;
+
+ spi_dev_set_gpio(spi_dev_gpio_srdy, SPI_DEV_GPIOLEVEL_HIGH);
+
+ if (count % 2 == 0) {
+ spi_dev_receive(rxbuf, SPI_DEV_MAX_PACKET_SIZE);
+ for (i = 1 ; i < SPI_DEV_MAX_PACKET_SIZE ; i++) {
+ if (rxbuf[i] != txbuf[i]) {
+ failcount++;
+ spi_os_trace_dump("spi_scenario_phy rx fail",
+ &rxbuf[i-8], 16);
+ SPI_OS_TRACE_MID(("%s %d count %d/%d\n",
+ "spi_scenario_physical test receiving fail",
+ i, failcount, count));
+ i = sizeof(rxbuf);
+ break;
+ }
+ }
+ } else
+ spi_dev_send(txbuf, SPI_DEV_MAX_PACKET_SIZE);
+
+ spi_os_sleep(SPI_FEATURE_TEST_DURATION);
+
+#endif
+ count++;
+ SPI_OS_TRACE_MID(("%s %d/%d\n",
+ "spi_scenario_physical test receiving result count",
+ failcount, count));
+ }
+}
+
+
+SPI_OS_TIMER_CALLBACK(spi_test_timer_callback)
+{
+ SPI_OS_TRACE_MID(("spi_test_timer_callback\n"));
+ _scenario_sending(0);
+}
+
+static char tempdata1[135]; /* temp code. becuase can not allocate */
+static char tempdata2[367]; /* temp code. becuase can not allocate */
+static char tempdata3[1057]; /* temp code. becuase can not allocate */
+static char tempdata4[35]; /* temp code. becuase can not allocate */
+static char tempdata5[2079]; /* temp code. becuase can not allocate */
+static char tempdata6[200]; /* temp code. becuase can not allocate */
+static char tempdata7[2052]; /* temp code. becuase can not allocate */
+
+static void _scenario_sending(int param)
+{
+ #define NB_COUNT 50
+ #define NB_STEP 7
+ static int step;
+ static int duration;
+ static int count;
+ static void *timer_id;
+
+ char *data = NULL;
+ int i, value;
+ struct DATABYSTEP_T {
+ SPI_MAIN_MSG_T type;
+ unsigned int size;
+ char *buf;
+ } databystep[NB_STEP] = {
+ {SPI_MAIN_MSG_IPC_SEND, 135, tempdata1},
+ {SPI_MAIN_MSG_IPC_SEND, 187, tempdata2},
+ {SPI_MAIN_MSG_RAW_SEND, 1057, tempdata3},
+ {SPI_MAIN_MSG_IPC_SEND, 35, tempdata4},
+ {SPI_MAIN_MSG_RAW_SEND, 2079, tempdata5},
+ {SPI_MAIN_MSG_IPC_SEND, 100, tempdata6},
+ {SPI_MAIN_MSG_RAW_SEND, 2052, tempdata7}
+ };
+
+ if (spi_test_scenario_mode == SPI_TEST_SCENARIO_SLAVE_SENDING)
+ data = databystep[step].buf;
+
+ /* param is 0 to fix duration. */
+ /* call this function with param to change timer duration. */
+ if (param != 0)
+ duration = param;
+
+ if (spi_test_scenario_mode != SPI_TEST_SCENARIO_SLAVE_SENDING)
+ data = (char *)spi_os_malloc(databystep[step].size);
+
+ spi_os_memset(data, 0x00, databystep[step].size);
+
+ SPI_OS_TRACE_MID(("spi _scenario_sending step %d\n", step));
+
+ /* generate data to send, It is serial number from 0 to 99 */
+ for (i = 0 ; i < databystep[step].size ; i++)
+ data[i] = i%100;
+
+ do {
+#ifdef SPI_FEATURE_OMAP4430
+ if (spi_is_ready() != 0) {
+ struct spi_os_msg *msg;
+ SPI_MAIN_MSG_T signal_code;
+ signal_code = databystep[step].type;
+
+ msg = (struct spi_os_msg *)
+ spi_os_malloc(sizeof(struct spi_os_msg));
+ msg->signal_code = signal_code;
+ msg->data_length = databystep[step].size;
+ msg->data = data;
+
+ spi_receive_msg_from_app(msg);
+ spi_main_send_signal(signal_code);
+ break;
+ } else
+ spi_os_sleep(50);
+#elif defined SPI_FEATURE_SC8800G
+ if (app_send_data_to_spi(databystep[step].type,
+ data, databystep[step].size) == 0)
+ /* send fail */
+ spi_os_sleep(50);
+ else
+ /* send success */
+ break;
+#endif
+ } while (1);
+
+ if (spi_test_scenario_mode == SPI_TEST_SCENARIO_MASTER_SENDING)
+ return;
+
+ step++;
+ count++;
+ step %= NB_STEP;
+
+ if (timer_id == 0)
+ timer_id = spi_os_create_timer("spi_test_timer",
+ spi_test_timer_callback, step, duration);
+
+ if (timer_id == 0) {
+ SPI_OS_TRACE_MID(("spi _scenario_sending invalid timer id\n"));
+ return;
+ }
+
+ SPI_OS_TRACE_MID(("spi _scenario_sending timer %x\n", timer_id));
+ SPI_OS_TRACE_MID(("spi _scenario_sending start timer count %d\n",
+ count));
+
+ if (count == NB_COUNT) {
+ spi_os_stop_timer(timer_id);
+ return;
+ }
+
+ value = spi_os_start_timer(timer_id, spi_test_timer_callback,
+ step, duration);
+ SPI_OS_TRACE_MID(("spi _scenario_sending start timer%d\n", value));
+
+ #undef NB_STEP
+}
+
+
+void spi_test_run(enum SPI_TEST_SCENARIO_T scenario, int param)
+{
+ SPI_OS_TRACE_MID(("spi_test_run %d\n", (int) scenario));
+
+ if (scenario == SPI_TEST_SCENARIO_NONE)
+ return;
+
+ spi_test_scenario_mode = scenario;
+
+ switch ((int)scenario) {
+ case SPI_TEST_SCENARIO_PHYSICAL:
+ _scenario_physical();
+ break;
+ case SPI_TEST_SCENARIO_MASTER_SENDING:
+#ifdef SPI_FEATURE_MASTER
+ _scenario_sending(param);
+#endif
+ break;
+ case SPI_TEST_SCENARIO_SLAVE_SENDING:
+#ifdef SPI_FEATURE_SLAVE
+ _scenario_sending(param);
+#endif
+ break;
+ case SPI_TEST_SCENARIO_COMPLEX_SENDING:
+ _scenario_sending(param);
+ break;
+ case SPI_TEST_SCENARIO_NONE:
+ default:
+ break;
+ }
+}
diff --git a/drivers/phone_svn/ipc_spi/spi_test.h b/drivers/phone_svn/ipc_spi/spi_test.h
new file mode 100644
index 0000000..251d057
--- /dev/null
+++ b/drivers/phone_svn/ipc_spi/spi_test.h
@@ -0,0 +1,14 @@
+#ifndef __SPI_TEST_H__
+#define __SPI_TEST_H__
+
+enum SPI_TEST_SCENARIO_T {
+ SPI_TEST_SCENARIO_NONE,
+ SPI_TEST_SCENARIO_PHYSICAL,
+ SPI_TEST_SCENARIO_MASTER_SENDING,
+ SPI_TEST_SCENARIO_SLAVE_SENDING,
+ SPI_TEST_SCENARIO_COMPLEX_SENDING,
+};
+
+extern enum SPI_TEST_SCENARIO_T spi_test_scenario_mode;
+extern void spi_test_run(enum SPI_TEST_SCENARIO_T scenario, int param);
+#endif
diff --git a/drivers/phone_svn/svnet/Makefile b/drivers/phone_svn/svnet/Makefile
new file mode 100644
index 0000000..42fad44
--- /dev/null
+++ b/drivers/phone_svn/svnet/Makefile
@@ -0,0 +1,5 @@
+svnet-y := main.o pdp.o
+
+svnet-y += sipc4.o
+
+obj-$(CONFIG_PHONE_SVNET) += svnet.o
diff --git a/drivers/phone_svn/svnet/main.c b/drivers/phone_svn/svnet/main.c
new file mode 100644
index 0000000..2db9412
--- /dev/null
+++ b/drivers/phone_svn/svnet/main.c
@@ -0,0 +1,867 @@
+/**
+ * Samsung Virtual Network driver using OneDram device
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/*#define DEBUG */
+
+#if defined(DEBUG)
+#define NOISY_DEBUG
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/list.h>
+#include <linux/jiffies.h>
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+
+#include <linux/if_phonet.h>
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+
+#ifdef CONFIG_HAS_WAKELOCK
+#include <linux/wakelock.h>
+
+#define DEFAULT_RAW_WAKE_TIME (6*HZ)
+#define DEFAULT_FMT_WAKE_TIME (HZ/2)
+#endif
+
+#if defined(NOISY_DEBUG)
+# define _dbg(dev, format, arg...) dev_dbg(dev, format, ## arg)
+#else
+# define _dbg(dev, format, arg...) do { } while (0)
+#endif
+
+#include "sipc.h"
+#include "pdp.h"
+
+#define SVNET_DEV_ADDR 0xa0
+
+enum {
+ SVNET_NORMAL = 0,
+ SVNET_RESET,
+ SVNET_EXIT,
+ SVNET_MAX,
+};
+
+struct svnet_stat {
+ unsigned int st_wq_state;
+ unsigned long st_recv_evt;
+ unsigned long st_recv_pkt_ph;
+ unsigned long st_recv_pkt_pdp;
+ unsigned long st_do_write;
+ unsigned long st_do_read;
+ unsigned long st_do_rx;
+};
+static struct svnet_stat stat;
+
+struct svnet_evt {
+ struct list_head list;
+ u32 event;
+};
+
+struct svnet_evt_head {
+ struct list_head list;
+ u32 len;
+ spinlock_t lock;
+};
+
+struct svnet {
+ struct net_device *ndev;
+ const struct attribute_group *group;
+
+ struct workqueue_struct *wq;
+ struct work_struct work_read;
+ struct delayed_work work_write;
+ struct delayed_work work_rx;
+
+ struct work_struct work_exit;
+ int exit_flag;
+
+ struct sk_buff_head txq;
+ struct svnet_evt_head rxq;
+
+ struct sipc *si;
+#ifdef CONFIG_HAS_WAKELOCK
+ struct wake_lock wlock;
+ long wake_time; /* jiffies */ /* wake time for not fmt packet */
+ long wake_process_time; /* jiffies */ /* processing wake time */
+#endif
+};
+
+static struct svnet *svnet_dev;
+
+#ifdef CONFIG_HAS_WAKELOCK
+static inline void _wake_lock_init(struct svnet *sn)
+{
+ wake_lock_init(&sn->wlock, WAKE_LOCK_SUSPEND, "svnet");
+ sn->wake_time = DEFAULT_RAW_WAKE_TIME;
+ sn->wake_process_time = DEFAULT_FMT_WAKE_TIME;
+}
+
+static inline void _wake_lock_destroy(struct svnet *sn)
+{
+ wake_lock_destroy(&sn->wlock);
+}
+
+static inline void _wake_lock_timeout(struct svnet *sn)
+{
+ wake_lock_timeout(&sn->wlock, sn->wake_time);
+}
+
+void _non_fmt_wakelock_timeout(void)
+{
+ if (svnet_dev)
+ _wake_lock_timeout(svnet_dev);
+}
+
+static inline void _wake_process_lock_timeout(struct svnet *sn)
+{
+ wake_lock_timeout(&sn->wlock, sn->wake_process_time);
+}
+
+void _fmt_wakelock_timeout(void)
+{
+ if (svnet_dev)
+ _wake_process_lock_timeout(svnet_dev);
+}
+
+static inline void _wake_lock_settime(struct svnet *sn, long time)
+{
+ if (sn)
+ sn->wake_time = time;
+}
+
+static inline long _wake_lock_gettime(struct svnet *sn)
+{
+ return sn ? sn->wake_time : DEFAULT_RAW_WAKE_TIME;
+}
+#else
+#define _wake_lock_init(sn) do { } while (0)
+#define _wake_lock_destroy(sn) do { } while (0)
+#define _wake_lock_timeout(sn) do { } while (0)
+#define _wake_process_lock_timeout(sn) do { } while (0)
+#define _non_fmt_wakelock_timeout() do { } while (0)
+#define _fmt_wakelock_timeout() do { } while (0)
+#define _wake_lock_settime(sn, time) do { } while (0)
+#define _wake_lock_gettime(sn) (0)
+#endif
+
+static unsigned long long tmp_itor;
+static unsigned long long tmp_xtow;
+static unsigned long long time_max_itor;
+static unsigned long long time_max_xtow;
+static unsigned long long time_max_read;
+static unsigned long long time_max_write;
+
+/*
+extern unsigned long long time_max_semlat;
+*/
+static int _queue_evt(struct svnet_evt_head *h, u32 event);
+
+static ssize_t show_version(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "Samsung IPC version %s\n", sipc_version);
+}
+
+static ssize_t show_waketime(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ char *p = buf;
+ unsigned int msec;
+ unsigned long j;
+
+ if (!svnet_dev)
+ return 0;
+
+ j = _wake_lock_gettime(svnet_dev);
+ msec = jiffies_to_msecs(j);
+ p += sprintf(p, "%u\n", msec);
+
+ return p - buf;
+}
+
+static ssize_t store_waketime(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ unsigned long msec;
+ unsigned long j;
+ int r;
+
+ if (!svnet_dev)
+ return count;
+
+ r = strict_strtoul(buf, 10, &msec);
+ if (r)
+ return count;
+
+ j = msecs_to_jiffies(msec);
+ _wake_lock_settime(svnet_dev, j);
+
+ return count;
+}
+
+static inline int _show_stat(char *buf)
+{
+ char *p = buf;
+
+ p += sprintf(p, "Stat --------\n");
+ p += sprintf(p, "\twork state: %d\n", stat.st_wq_state);
+ p += sprintf(p, "\trecv mailbox: %lu\n", stat.st_recv_evt);
+ p += sprintf(p, "\trecv phonet: %lu\n", stat.st_recv_pkt_ph);
+ p += sprintf(p, "\trecv packet: %lu\n", stat.st_recv_pkt_pdp);
+ p += sprintf(p, "\twrite count: %lu\n", stat.st_do_write);
+ p += sprintf(p, "\tread count: %lu\n", stat.st_do_read);
+ p += sprintf(p, "\trx count: %lu\n", stat.st_do_rx);
+ p += sprintf(p, "\n");
+
+ return p - buf;
+}
+
+static ssize_t show_latency(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ char *p = buf;
+
+ p += sprintf(p, "Max read latency: %12llu ns\n", time_max_itor);
+ p += sprintf(p, "Max read time: %12llu ns\n", time_max_read);
+ p += sprintf(p, "Max write latency: %12llu ns\n", time_max_xtow);
+ p += sprintf(p, "Max write time: %12llu ns\n", time_max_write);
+ /*p += sprintf(p, "Max sem. latency: %12llu ns\n", time_max_semlat);*/
+
+ return p - buf;
+}
+
+static ssize_t show_debug(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ char *p = buf;
+
+ if (!svnet_dev)
+ return 0;
+
+ p += _show_stat(p);
+
+ p += sprintf(p, "Event queue -----\n");
+ p += sprintf(p, "\tTX queue\t%u\n", skb_queue_len(&svnet_dev->txq));
+ p += sprintf(p, "\tRX queue\t%u\n", svnet_dev->rxq.len);
+
+ p += sipc_debug_show(svnet_dev->si, p);
+
+ return p - buf;
+}
+
+static ssize_t store_debug(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ if (!svnet_dev)
+ return count;
+
+ switch (buf[0]) {
+ case 'R':
+ sipc_debug(svnet_dev->si, buf);
+ break;
+ default:
+
+ break;
+ }
+
+ return count;
+}
+
+static ssize_t store_whitelist(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ if (!svnet_dev)
+ return count;
+
+ switch (buf[0]) {
+ case 0x7F:
+ return sipc_whitelist(svnet_dev->si, buf, count);
+ break;
+ default:
+
+ break;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR(latency, S_IRUGO, show_latency, NULL);
+static DEVICE_ATTR(waketime, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_waketime, store_waketime);
+static DEVICE_ATTR(debug, S_IRUGO | S_IWUSR, show_debug, store_debug);
+static DEVICE_ATTR(whitelist, S_IRUSR | S_IWUSR, NULL, store_whitelist);
+
+static struct attribute *svnet_attributes[] = {
+ &dev_attr_version.attr,
+ &dev_attr_waketime.attr,
+ &dev_attr_debug.attr,
+ &dev_attr_latency.attr,
+ &dev_attr_whitelist.attr,
+ NULL
+};
+
+static const struct attribute_group svnet_group = {
+ .attrs = svnet_attributes,
+};
+
+
+int vnet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct svnet *sn;
+ struct pdp_priv *priv;
+
+ dev_dbg(&ndev->dev, "recv inet packet %p: %d bytes\n", skb, skb->len);
+ stat.st_recv_pkt_pdp++;
+
+ priv = netdev_priv(ndev);
+ if (!priv)
+ goto drop;
+
+ sn = netdev_priv(priv->parent);
+ if (!sn)
+ goto drop;
+
+ if (!tmp_xtow)
+ tmp_xtow = cpu_clock(smp_processor_id());
+
+ skb_queue_tail(&sn->txq, skb);
+
+ _wake_process_lock_timeout(sn);
+ queue_delayed_work(sn->wq, &sn->work_write, 0);
+
+ return NETDEV_TX_OK;
+
+drop:
+ ndev->stats.tx_dropped++;
+
+ return NETDEV_TX_OK;
+}
+
+static int svnet_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct svnet *sn;
+
+ if (skb->protocol != __constant_htons(ETH_P_PHONET)) {
+ dev_err(&ndev->dev, "recv not a phonet message\n");
+ goto drop;
+ }
+
+ stat.st_recv_pkt_ph++;
+ dev_dbg(&ndev->dev, "recv packet %p: %d bytes\n", skb, skb->len);
+
+ sn = netdev_priv(ndev);
+
+ if (sipc_check_skb(sn->si, skb)) {
+ sipc_do_cmd(sn->si, skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (!tmp_xtow)
+ tmp_xtow = cpu_clock(smp_processor_id());
+
+ skb_queue_tail(&sn->txq, skb);
+
+ _wake_process_lock_timeout(sn);
+ queue_delayed_work(sn->wq, &sn->work_write, 0);
+
+ return NETDEV_TX_OK;
+
+drop:
+ dev_kfree_skb(skb);
+ ndev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+}
+
+static int _queue_evt(struct svnet_evt_head *h, u32 event)
+{
+ unsigned long flags;
+ struct svnet_evt *e;
+
+ e = kmalloc(sizeof(struct svnet_evt), GFP_ATOMIC);
+ if (!e)
+ return -ENOMEM;
+
+ e->event = event;
+
+ spin_lock_irqsave(&h->lock, flags);
+ list_add_tail(&e->list, &h->list);
+ h->len++;
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ return 0;
+}
+
+static void _queue_purge(struct svnet_evt_head *h)
+{
+ unsigned long flags;
+ struct svnet_evt *e, *next;
+
+ spin_lock_irqsave(&h->lock, flags);
+ list_for_each_entry_safe(e, next, &h->list, list) {
+ list_del(&e->list);
+ h->len--;
+ kfree(e);
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static u32 _dequeue_evt(struct svnet_evt_head *h)
+{
+ unsigned long flags;
+ struct list_head *p;
+ struct svnet_evt *e;
+ u32 event;
+
+ spin_lock_irqsave(&h->lock, flags);
+ p = h->list.next;
+ if (p == &h->list) {
+ e = NULL;
+ event = 0;
+ } else {
+ e = list_entry(p, struct svnet_evt, list);
+ list_del(&e->list);
+ h->len--;
+ event = e->event;
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+
+ if (e)
+ kfree(NULL);
+
+ return event;
+}
+
+static int _proc_private_event(struct svnet *sn, u32 evt)
+{
+ switch (evt) {
+ case SIPC_EXIT_MB:
+ dev_err(&sn->ndev->dev, "Modem crash message received\n");
+ sn->exit_flag = SVNET_EXIT;
+ break;
+ case SIPC_RESET_MB:
+ dev_err(&sn->ndev->dev, "Modem reset message received\n");
+ sn->exit_flag = SVNET_RESET;
+ break;
+ default:
+ return 0;
+ }
+
+ /* //block for pdp_activate fail - jongmoon.suh
+ queue_work(sn->wq, &sn->work_exit);
+ */
+
+ return 1;
+}
+
+static void svnet_queue_event(u32 evt, void *data)
+{
+ struct net_device *ndev = (struct net_device *)data;
+ struct svnet *sn;
+ int r;
+
+ if (!tmp_itor)
+ tmp_itor = cpu_clock(smp_processor_id());
+
+ stat.st_recv_evt++;
+
+ if (!ndev)
+ return;
+
+ sn = netdev_priv(ndev);
+ if (!sn)
+ return;
+
+ r = _proc_private_event(sn, evt);
+ if (r)
+ return;
+
+ r = _queue_evt(&sn->rxq, evt);
+ if (r) {
+ dev_err(&sn->ndev->dev, "Not enough memory: event skipped\n");
+ return;
+ }
+
+ _wake_process_lock_timeout(sn);
+ queue_work(sn->wq, &sn->work_read);
+}
+
+static int svnet_open(struct net_device *ndev)
+{
+ struct svnet *sn = netdev_priv(ndev);
+
+ dev_dbg(&ndev->dev, "%s\n", __func__);
+
+ /* TODO: check modem state */
+
+ if (!sn->si) {
+ sn->si = sipc_open(svnet_queue_event, ndev);
+ if (IS_ERR(sn->si)) {
+ dev_err(&ndev->dev, "IPC init error\n");
+ return PTR_ERR(sn->si);
+ }
+ sn->exit_flag = SVNET_NORMAL;
+ }
+
+ netif_wake_queue(ndev);
+ return 0;
+}
+
+static int svnet_close(struct net_device *ndev)
+{
+ struct svnet *sn = netdev_priv(ndev);
+
+ dev_dbg(&ndev->dev, "%s\n", __func__);
+
+ if (sn->wq)
+ flush_workqueue(sn->wq);
+ skb_queue_purge(&sn->txq);
+
+ if (sn->si)
+ sipc_close(&sn->si);
+
+ netif_stop_queue(ndev);
+
+ if (sn->wq)
+ flush_workqueue(sn->wq);
+ skb_queue_purge(&sn->txq);
+
+ return 0;
+}
+
+static int svnet_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+ struct if_phonet_req *req = (struct if_phonet_req *)ifr;
+
+ switch (cmd) {
+ case SIOCPNGAUTOCONF:
+ req->ifr_phonet_autoconf.device = SVNET_DEV_ADDR;
+ return 0;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static const struct net_device_ops svnet_ops = {
+ .ndo_open = svnet_open,
+ .ndo_stop = svnet_close,
+ .ndo_start_xmit = svnet_xmit,
+ .ndo_do_ioctl = svnet_ioctl,
+};
+
+static void svnet_setup(struct net_device *ndev)
+{
+ ndev->features = 0;
+ ndev->netdev_ops = &svnet_ops;
+ ndev->header_ops = &phonet_header_ops;
+ ndev->type = ARPHRD_PHONET;
+ ndev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ ndev->mtu = PHONET_MAX_MTU;
+ ndev->hard_header_len = 1;
+ ndev->dev_addr[0] = SVNET_DEV_ADDR;
+ ndev->addr_len = 1;
+ ndev->tx_queue_len = 1000;
+
+/* ndev->destructor = free_netdev; */
+}
+
+static void svnet_read_wq(struct work_struct *work)
+{
+ struct svnet *sn = container_of(work,
+ struct svnet, work_read);
+ u32 event;
+ int r = 0;
+ int contd = 0;
+ unsigned long long t, d;
+
+ t = cpu_clock(smp_processor_id());
+ if (tmp_itor) {
+ d = t - tmp_itor;
+ _dbg(&sn->ndev->dev, "int_to_read %llu ns\n", d);
+ tmp_itor = 0;
+ if (time_max_itor < d)
+ time_max_itor = d;
+ }
+
+ dev_dbg(&sn->ndev->dev, "%s\n", __func__);
+ stat.st_do_read++;
+
+ stat.st_wq_state = 1;
+ event = _dequeue_evt(&sn->rxq);
+ while (event) {
+ /* isn't it possible that merge the events? */
+ dev_dbg(&sn->ndev->dev, "event %x\n", event);
+
+ if (sn->si) {
+ r = sipc_read(sn->si, event, &contd);
+ if (r < 0) {
+ dev_err(&sn->ndev->dev, "ret %d -> queue %x\n",
+ r, event);
+ _queue_evt(&sn->rxq, event);
+ break;
+ }
+ } else {
+ dev_err(&sn->ndev->dev,
+ "IPC not work, skip event %x\n", event);
+ }
+ event = _dequeue_evt(&sn->rxq);
+ }
+
+ if (contd > 0)
+ queue_delayed_work(sn->wq, &sn->work_rx, 0);
+
+ switch (r) {
+ case -EINVAL:
+ dev_err(&sn->ndev->dev, "Invalid argument\n");
+ break;
+ case -EBADMSG:
+ dev_err(&sn->ndev->dev, "Bad message, purge the buffer\n");
+ break;
+ case -ETIMEDOUT:
+ dev_err(&sn->ndev->dev, "Timed out\n");
+ break;
+ default:
+
+ break;
+ }
+
+ stat.st_wq_state = 2;
+
+ d = cpu_clock(smp_processor_id()) - t;
+ _dbg(&sn->ndev->dev, "read_time %llu ns\n", d);
+ if (d > time_max_read)
+ time_max_read = d;
+}
+
+static void svnet_write_wq(struct work_struct *work)
+{
+ struct svnet *sn = container_of(work,
+ struct svnet, work_write.work);
+ int r;
+ unsigned long long t, d;
+
+ t = cpu_clock(smp_processor_id());
+ if (tmp_xtow) {
+ d = t - tmp_xtow;
+ _dbg(&sn->ndev->dev, "xmit_to_write %llu ns\n", d);
+ tmp_xtow = 0;
+ if (d > time_max_xtow)
+ time_max_xtow = d;
+ }
+
+ dev_dbg(&sn->ndev->dev, "%s\n", __func__);
+ stat.st_do_write++;
+
+ stat.st_wq_state = 3;
+ if (sn->si)
+ r = sipc_write(sn->si, &sn->txq);
+ else {
+ skb_queue_purge(&sn->txq);
+ dev_err(&sn->ndev->dev, "IPC not work, drop packet\n");
+ r = 0;
+ }
+
+ switch (r) {
+ case -ENOSPC:
+ dev_err(&sn->ndev->dev, "buffer is full, wait...\n");
+ queue_delayed_work(sn->wq, &sn->work_write, HZ/10);
+ break;
+ case -EINVAL:
+ dev_err(&sn->ndev->dev, "Invalid arugment\n");
+ break;
+ case -ENXIO:
+ dev_err(&sn->ndev->dev, "IPC not work, purge the queue\n");
+ break;
+ case -ETIMEDOUT:
+ dev_err(&sn->ndev->dev, "Timed out\n");
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+
+ stat.st_wq_state = 4;
+ d = cpu_clock(smp_processor_id()) - t;
+ _dbg(&sn->ndev->dev, "write_time %llu ns\n", d);
+ if (d > time_max_write)
+ time_max_write = d;
+}
+
+static void svnet_rx_wq(struct work_struct *work)
+{
+ struct svnet *sn = container_of(work,
+ struct svnet, work_rx.work);
+ int r = 0;
+
+ dev_dbg(&sn->ndev->dev, "%s\n", __func__);
+ stat.st_do_rx++;
+
+ stat.st_wq_state = 5;
+ if (sn->si)
+ r = sipc_rx(sn->si);
+
+ if (r > 0)
+ queue_delayed_work(sn->wq, &sn->work_rx, HZ/10);
+
+ stat.st_wq_state = 6;
+}
+
+static char *uevent_envs[SVNET_MAX] = {
+ "",
+ "MAILBOX=cp_reset", /* reset */
+ "MAILBOX=cp_exit", /* exit */
+};
+static void svnet_exit_wq(struct work_struct *work)
+{
+ struct svnet *sn = container_of(work,
+ struct svnet, work_exit);
+ char *envs[2] = { NULL, NULL };
+
+ dev_dbg(&sn->ndev->dev, "%s: %d\n", __func__, sn->exit_flag);
+
+ if (sn->exit_flag == SVNET_NORMAL || sn->exit_flag >= SVNET_MAX)
+ return;
+
+ envs[0] = uevent_envs[sn->exit_flag];
+ kobject_uevent_env(&sn->ndev->dev.kobj, KOBJ_OFFLINE, envs);
+
+ _queue_purge(&sn->rxq);
+ skb_queue_purge(&sn->txq);
+
+ if (sn->exit_flag == SVNET_EXIT)
+ sipc_ramdump(sn->si);
+
+#if 0
+ rtnl_lock();
+ if (netif_running(sn->ndev))
+ dev_close(sn->ndev);
+ rtnl_unlock();
+#endif
+}
+
+static inline void _init_data(struct svnet *sn)
+{
+ INIT_WORK(&sn->work_read, svnet_read_wq);
+ INIT_DELAYED_WORK(&sn->work_write, svnet_write_wq);
+ INIT_DELAYED_WORK(&sn->work_rx, svnet_rx_wq);
+ INIT_WORK(&sn->work_exit, svnet_exit_wq);
+
+ INIT_LIST_HEAD(&sn->rxq.list);
+ spin_lock_init(&sn->rxq.lock);
+ sn->rxq.len = 0;
+ skb_queue_head_init(&sn->txq);
+}
+
+static void _free(struct svnet *sn)
+{
+ if (!sn)
+ return;
+
+ _wake_lock_destroy(sn);
+
+ if (sn->group)
+ sysfs_remove_group(&sn->ndev->dev.kobj, &svnet_group);
+
+ if (sn->wq) {
+ flush_workqueue(sn->wq);
+ destroy_workqueue(sn->wq);
+ }
+
+ if (sn->si) {
+ sipc_close(&sn->si);
+ sipc_exit();
+ }
+
+ if (sn->ndev)
+ unregister_netdev(sn->ndev);
+
+ /* sn is ndev's priv */
+ free_netdev(sn->ndev);
+}
+
+static int __init svnet_init(void)
+{
+ int r;
+ struct svnet *sn = NULL;
+ struct net_device *ndev;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+ ndev = alloc_netdev(sizeof(struct svnet), "svnet%d", svnet_setup);
+ if (!ndev) {
+ r = -ENOMEM;
+ goto err;
+ }
+ netif_stop_queue(ndev);
+ sn = netdev_priv(ndev);
+
+ _wake_lock_init(sn);
+
+ r = register_netdev(ndev);
+ if (r) {
+ dev_err(&ndev->dev, "failed to register netdev\n");
+ goto err;
+ }
+ sn->ndev = ndev;
+
+ _init_data(sn);
+
+ sn->wq = create_workqueue("svnetd");
+ if (!sn->wq) {
+ dev_err(&ndev->dev, "failed to create a workqueue\n");
+ goto err;
+ }
+
+ r = sysfs_create_group(&sn->ndev->dev.kobj, &svnet_group);
+ if (r) {
+ dev_err(&ndev->dev, "failed to create sysfs group\n");
+ goto err;
+ }
+ sn->group = &svnet_group;
+
+ dev_dbg(&ndev->dev, "Svnet dev: %p\n", sn);
+ svnet_dev = sn;
+
+ return 0;
+
+err:
+ _free(sn);
+ return r;
+}
+
+static void __exit svnet_exit(void)
+{
+
+ _free(svnet_dev);
+ svnet_dev = NULL;
+}
+
+module_init(svnet_init);
+module_exit(svnet_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Suchang Woo <suchang.woo@samsung.com>");
+MODULE_DESCRIPTION("Samsung Virtual network interface");
diff --git a/drivers/phone_svn/svnet/main.h b/drivers/phone_svn/svnet/main.h
new file mode 100644
index 0000000..74685e9
--- /dev/null
+++ b/drivers/phone_svn/svnet/main.h
@@ -0,0 +1,5 @@
+/*add interface for sipc files*/
+
+void _non_fmt_wakelock_timeout(void);
+
+void _fmt_wakelock_timeout(void);
diff --git a/drivers/phone_svn/svnet/pdp.c b/drivers/phone_svn/svnet/pdp.c
new file mode 100644
index 0000000..c5a06dc
--- /dev/null
+++ b/drivers/phone_svn/svnet/pdp.c
@@ -0,0 +1,100 @@
+/**
+ * Samsung Virtual Network driver using OneDram device
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* #define DEBUG */
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+
+#include "pdp.h"
+
+static int vnet_open(struct net_device *ndev)
+{
+ netif_start_queue(ndev);
+ return 0;
+}
+
+static int vnet_stop(struct net_device *ndev)
+{
+ netif_stop_queue(ndev);
+ return 0;
+}
+
+static struct net_device_ops vnet_ops = {
+ .ndo_open = vnet_open,
+ .ndo_stop = vnet_stop,
+/* .ndo_tx_timeout = vnet_tx_timeout,
+ .ndo_start_xmit = vnet_start_xmit,*/
+};
+
+static void vnet_setup(struct net_device *ndev)
+{
+ vnet_ops.ndo_start_xmit = vnet_start_xmit;
+
+ ndev->netdev_ops = &vnet_ops;
+ ndev->type = ARPHRD_PPP;
+ ndev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+ ndev->hard_header_len = 0;
+ ndev->addr_len = 0;
+ ndev->tx_queue_len = 1000;
+ ndev->mtu = ETH_DATA_LEN;
+ ndev->watchdog_timeo = 5 * HZ;
+}
+
+struct net_device *create_pdp(int channel, struct net_device *parent)
+{
+ int r;
+ struct pdp_priv *priv;
+ struct net_device *ndev;
+ char devname[IFNAMSIZ];
+
+ if (!parent)
+ return ERR_PTR(-EINVAL);
+
+ sprintf(devname, "pdp%d", channel - 1);
+ ndev = alloc_netdev(sizeof(struct pdp_priv), devname, vnet_setup);
+ if (!ndev)
+ return ERR_PTR(-ENOMEM);
+
+ priv = netdev_priv(ndev);
+ priv->channel = channel;
+ priv->parent = parent;
+
+ r = register_netdev(ndev);
+ if (r) {
+ free_netdev(ndev);
+ return ERR_PTR(r);
+ }
+
+ return ndev;
+}
+
+void destroy_pdp(struct net_device **ndev)
+{
+ if (!ndev || !*ndev)
+ return;
+
+ unregister_netdev(*ndev);
+ free_netdev(*ndev);
+ *ndev = NULL;
+}
diff --git a/drivers/phone_svn/svnet/pdp.h b/drivers/phone_svn/svnet/pdp.h
new file mode 100644
index 0000000..804b0f3
--- /dev/null
+++ b/drivers/phone_svn/svnet/pdp.h
@@ -0,0 +1,35 @@
+/**
+ * SAMSUNG MODEM IPC header
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __PACKET_DATA_PROTOCOL_H__
+#define __PACKET_DATA_PROTOCOL_H__
+
+#include <linux/netdevice.h>
+
+struct pdp_priv {
+ int channel;
+ struct net_device *parent;
+};
+
+extern struct net_device *create_pdp(int channel, struct net_device *parent);
+extern void destroy_pdp(struct net_device **);
+extern int vnet_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+
+#endif /* __PACKET_DATA_PROTOCOL_H__ */
diff --git a/drivers/phone_svn/svnet/sipc.h b/drivers/phone_svn/svnet/sipc.h
new file mode 100644
index 0000000..af9400b
--- /dev/null
+++ b/drivers/phone_svn/svnet/sipc.h
@@ -0,0 +1,64 @@
+/**
+ * SAMSUNG MODEM IPC header
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __SAMSUNG_IPC_H__
+#define __SAMSUNG_IPC_H__
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+extern const char *sipc_version;
+
+/*
+#if 1
+# include "sipc4.h"
+#else
+# error "Unknown version"
+#endif
+*/
+
+#define SIPC_RESET_MB 0xFFFFFF7E /* -2 & ~(INT_VALID) */
+#define SIPC_EXIT_MB 0xFFFFFF7F /* -1 & ~(INT_VALID) */
+
+struct sipc;
+
+extern struct sipc *sipc_open(void (*queue)(u32 mailbox, void *data),
+ struct net_device *ndev);
+extern void sipc_close(struct sipc **);
+
+extern void sipc_exit(void);
+
+extern int sipc_write(struct sipc *, struct sk_buff_head *);
+extern int sipc_read(struct sipc *, u32 mailbox, int *cond);
+extern int sipc_rx(struct sipc *);
+
+
+/* TODO: use PN_CMD ?? */
+extern int sipc_check_skb(struct sipc *, struct sk_buff *skb);
+extern int sipc_do_cmd(struct sipc *, struct sk_buff *skb);
+
+extern ssize_t sipc_debug_show(struct sipc *, char *);
+extern int sipc_debug(struct sipc *, const char *);
+extern int sipc_whitelist(struct sipc *si, const char *buf, size_t count);
+
+extern void sipc_ramdump(struct sipc *);
+
+#endif /* __SAMSUNG_IPC_H__ */
diff --git a/drivers/phone_svn/svnet/sipc4.c b/drivers/phone_svn/svnet/sipc4.c
new file mode 100644
index 0000000..55aecf6
--- /dev/null
+++ b/drivers/phone_svn/svnet/sipc4.c
@@ -0,0 +1,2119 @@
+/**
+ * SAMSUNG MODEM IPC version 4
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+/* #define DEBUG */
+
+#if defined(DEBUG)
+#define NOISY_DEBUG
+#endif
+
+#include "pdp.h"
+#include "sipc.h"
+#include "sipc4.h"
+#include "main.h"
+#include <linux/vmalloc.h>
+#include <linux/circ_buf.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+
+#include <net/sock.h>
+#include <linux/if_ether.h>
+#include <linux/phonet.h>
+#include <net/phonet/phonet.h>
+
+#if defined(CONFIG_PHONE_IPC_SPI)
+#include <linux/phone_svn/ipc_spi.h>
+#else
+#if defined(CONFIG_PHONE_IPC_HSI)
+#include <linux/phone_svn/ipc_hsi.h>
+#endif
+#endif
+
+#if defined(CONFIG_KERNEL_DEBUG_SEC)
+#include <linux/kernel_sec_common.h>
+#define ERRMSG "Unknown CP Crash"
+static char cp_errmsg[65];
+static void _go_dump(struct sipc *si);
+#else
+#define _go_dump(si) do { } while (0)
+#endif
+
+#if defined(NOISY_DEBUG)
+static struct device *_dev;
+# define _dbg(format, arg...) \
+ dev_dbg(_dev, format, ## arg)
+#else
+# define _dbg(format, arg...) \
+ do { } while (0)
+#endif
+
+const char *sipc_version = "4.1";
+
+static const char hdlc_start[1] = { HDLC_START };
+static const char hdlc_end[1] = { HDLC_END };
+
+struct mailbox_data {
+ u16 mask_send;
+ u16 mask_req_ack;
+ u16 mask_res_ack;
+};
+
+static struct mailbox_data mb_data[IPCIDX_MAX] = {
+ {
+ .mask_send = MBD_SEND_FMT,
+ .mask_req_ack = MBD_REQ_ACK_FMT,
+ .mask_res_ack = MBD_RES_ACK_FMT,
+ },
+ {
+ .mask_send = MBD_SEND_RAW,
+ .mask_req_ack = MBD_REQ_ACK_RAW,
+ .mask_res_ack = MBD_RES_ACK_RAW,
+ },
+ {
+ .mask_send = MBD_SEND_RFS,
+ .mask_req_ack = MBD_REQ_ACK_RFS,
+ .mask_res_ack = MBD_RES_ACK_RFS,
+ },
+};
+
+/* semaphore latency */
+unsigned long long time_max_semlat;
+
+struct sipc;
+struct ringbuf;
+
+struct ringbuf_info {
+ unsigned int out_off;
+ unsigned int in_off;
+ unsigned int size;
+ int (*read)(struct sipc *si, int inbuf, struct ringbuf *rb);
+};
+
+struct ringbuf {
+ unsigned char *out_base;
+ unsigned char *in_base;
+ struct ringbuf_cont *cont;
+ struct ringbuf_info *info;
+};
+/*
+#define rb_size info->size
+#define rb_read info->read
+#define rb_out_head cont->out_head
+#define rb_out_tail cont->out_tail
+#define rb_in_head cont->in_head
+#define rb_in_tail cont->in_tail
+*/
+
+static int _read_fmt(struct sipc *si, int inbuf, struct ringbuf *rb);
+static int _read_raw(struct sipc *si, int inbuf, struct ringbuf *rb);
+static int _read_rfs(struct sipc *si, int inbuf, struct ringbuf *rb);
+
+static struct ringbuf_info rb_info[IPCIDX_MAX] = {
+ {
+ .out_off = FMT_OUT,
+ .in_off = FMT_IN,
+ .size = FMT_SZ,
+ .read = _read_fmt,
+ },
+ {
+ .out_off = RAW_OUT,
+ .in_off = RAW_IN,
+ .size = RAW_SZ,
+ .read = _read_raw,
+ },
+ {
+ .out_off = RFS_OUT,
+ .in_off = RFS_IN,
+ .size = RFS_SZ,
+ .read = _read_rfs,
+ },
+};
+
+#define FRAG_BLOCK_MAX (PAGE_SIZE - sizeof(struct list_head) \
+ - sizeof(u32) - sizeof(char *))
+struct frag_block {
+ struct list_head list;
+ u32 len;
+ char *ptr;
+ char buf[FRAG_BLOCK_MAX];
+};
+
+struct frag_list {
+ struct list_head list;
+ u8 msg_id;
+ u32 len;
+
+ struct list_head block_head;
+};
+
+struct frag_head {
+ struct list_head head;
+ unsigned long bitmap[FMT_ID_SIZE/BITS_PER_LONG];
+};
+
+struct frag_info {
+ struct sk_buff *skb;
+ unsigned int offset;
+ u8 msg_id;
+};
+
+struct sipc {
+ struct sipc_mapped *map;
+ struct ringbuf rb[IPCIDX_MAX];
+
+ struct resource *res;
+
+ void (*queue)(u32, void *);
+ void *queue_data;
+
+ /* for fragmentation */
+ u8 msg_id;
+ char *frag_buf;
+ struct frag_info frag;
+
+ /* for merging */
+ struct frag_head frag_map;
+
+ int od_rel; /* onedram authority release */
+
+ struct net_device *svndev;
+
+ const struct attribute_group *group;
+
+ struct sk_buff_head rfs_rx;
+};
+
+/* sizeof(struct phonethdr) + NET_SKB_PAD > SMP_CACHE_BYTES */
+
+/* SMP_CACHE_BYTES > sizeof(struct phonethdr) + NET_SKB_PAD */
+#define RFS_MTU (PAGE_SIZE - SMP_CACHE_BYTES)
+#define RFS_TX_RATE 4
+
+/* set at storage device */
+unsigned int factory_test_force_sleep;
+EXPORT_SYMBOL(factory_test_force_sleep);
+
+/* TODO: move PDP related codes to other source file */
+static DEFINE_MUTEX(pdp_mutex);
+static struct net_device *pdp_devs[PDP_MAX];
+static int pdp_cnt;
+unsigned long pdp_bitmap[PDP_MAX/BITS_PER_LONG];
+
+static void clear_pdp_wq(struct work_struct *work);
+static DECLARE_WORK(pdp_work, clear_pdp_wq);
+
+static ssize_t show_act(struct device *d,
+ struct device_attribute *attr, char *buf);
+static ssize_t show_deact(struct device *d,
+ struct device_attribute *attr, char *buf);
+static ssize_t store_act(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_deact(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static ssize_t show_suspend(struct device *d,
+ struct device_attribute *attr, char *buf);
+static ssize_t store_suspend(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t store_resume(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count);
+
+static DEVICE_ATTR(activate, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_act, store_act);
+static DEVICE_ATTR(deactivate, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_deact, store_deact);
+static DEVICE_ATTR(suspend, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_suspend, store_suspend);
+static DEVICE_ATTR(resume, S_IRUGO | S_IWUSR | S_IWGRP, NULL,
+ store_resume);
+
+static struct attribute *pdp_attributes[] = {
+ &dev_attr_activate.attr,
+ &dev_attr_deactivate.attr,
+ &dev_attr_suspend.attr,
+ &dev_attr_resume.attr,
+ NULL
+};
+
+static const struct attribute_group pdp_group = {
+ .name = "pdp",
+ .attrs = pdp_attributes,
+};
+
+
+#if defined(NOISY_DEBUG)
+#define DUMP_LIMIT 32
+static char dump_buf[64];
+void _dbg_dump(u8 *buf, int size)
+{
+ int i;
+ int len = 0;
+
+ if (!buf)
+ return;
+
+ if (size > DUMP_LIMIT)
+ size = DUMP_LIMIT;
+
+ for (i = 0; i < 32 && i < size; i++) {
+ len += sprintf(&dump_buf[len], "%02x ", buf[i]);
+ if ((i & 0xf) == 0xf) {
+ dump_buf[len] = '\0';
+ _dbg("dump %04x [ %s]\n", (i>>4), dump_buf);
+ len = 0;
+ }
+ }
+ if (len) {
+ dump_buf[len] = '\0';
+ _dbg("dump %04x [ %s]\n", i, dump_buf);
+ }
+}
+#else
+# define _dbg_dump(buf, size) do { } while (0)
+#endif
+
+static int cp_state = 1;
+void modem_state_changed(int state)
+{
+ printk(KERN_ERR "cp state change. state : %d\n", state);
+
+ cp_state = state;
+}
+EXPORT_SYMBOL(modem_state_changed);
+
+static int _get_auth(void)
+{
+ int r;
+ unsigned long long t, d;
+
+ t = cpu_clock(smp_processor_id());
+
+ r = onedram_get_auth(MB_CMD(MBC_REQ_SEM));
+
+ d = cpu_clock(smp_processor_id()) - t;
+ if (d > time_max_semlat)
+ time_max_semlat = d;
+
+ return r;
+}
+
+static void _put_auth(struct sipc *si)
+{
+ if (!si)
+ return;
+
+ onedram_put_auth(0);
+
+ if (si->od_rel && !onedram_rel_sem()) {
+ onedram_write_mailbox(MB_CMD(MBC_RES_SEM));
+ si->od_rel = 0;
+ }
+}
+
+static inline void _req_rel_auth(struct sipc *si)
+{
+ si->od_rel = 1;
+}
+
+static int _get_auth_try(void)
+{
+ return onedram_get_auth(0);
+}
+
+static void _check_buffer(struct sipc *si)
+{
+ int i;
+ u32 mailbox;
+
+#if 0
+ i = onedram_read_sem();
+ if (i != 0x1)
+ return;
+#endif
+ i = _get_auth_try();
+ if (i)
+ return;
+
+ mailbox = 0;
+
+ for (i = 0 ; i < IPCIDX_MAX; i++) {
+ int inbuf;
+ struct ringbuf *rb;
+
+ rb = &si->rb[i];
+ inbuf = CIRC_CNT(rb->cont->in_head,
+ rb->cont->in_tail, rb->info->size);
+ if (!inbuf)
+ continue;
+
+ mailbox |= mb_data[i].mask_send;
+ }
+ _put_auth(si);
+
+ if (mailbox)
+ si->queue(MB_DATA(mailbox), si->queue_data);
+}
+
+static void _do_command(struct sipc *si, u32 mailbox)
+{
+ int r;
+ u32 cmd = (mailbox & MBC_MASK) & ~(MB_CMD(0));
+
+ switch (cmd) {
+ case MBC_REQ_SEM:
+ r = onedram_rel_sem();
+ if (r) {
+ dev_dbg(&si->svndev->dev, "onedram in use, "
+ "defer releasing semaphore\n");
+ _req_rel_auth(si);
+ } else
+ onedram_write_mailbox(MB_CMD(MBC_RES_SEM));
+ break;
+ case MBC_RES_SEM:
+ /* do nothing */
+ break;
+ case MBC_PHONE_START:
+ onedram_write_mailbox(MB_CMD(MBC_INIT_END) | CP_BOOT_AIRPLANE
+ | AP_OS_ANDROID);
+ break;
+ case MBC_RESET:
+ printk(KERN_ERR "svnet reset mailbox msg : 0x%08x\n", mailbox);
+ si->queue(SIPC_RESET_MB, si->queue_data);
+ break;
+ case MBC_ERR_DISPLAY:
+ printk(KERN_ERR "svnet error display mailbox msg : 0x%08x\n",
+ mailbox);
+ si->queue(SIPC_EXIT_MB, si->queue_data);
+ break;
+ /* TODO : impletment other commands... */
+ default:
+ /* do nothing */
+
+ break;
+ }
+}
+
+void sipc_handler(u32 mailbox, void *data)
+{
+ struct sipc *si = (struct sipc *)data;
+
+ if (!si || !si->queue)
+ return;
+
+ dev_dbg(&si->svndev->dev, "recv mailbox %x\n", mailbox);
+
+#if defined(CONFIG_KERNEL_DEBUG_SEC)
+ if (mailbox == KERNEL_SEC_DUMP_AP_DEAD_ACK)
+ kernel_sec_set_cp_ack();
+#endif
+
+ if ((mailbox & MB_VALID) == 0) {
+ dev_err(&si->svndev->dev, "Invalid mailbox message: %x\n",
+ mailbox);
+ return;
+ }
+
+ if (mailbox & MB_COMMAND) {
+ _check_buffer(si);
+ _do_command(si, mailbox);
+ return;
+ }
+
+ si->queue(mailbox, si->queue_data);
+}
+
+static inline void _init_data(struct sipc *si, unsigned char *base)
+{
+ int i;
+
+ si->map = (struct sipc_mapped *)base;
+ si->map->magic = 0x0;
+ si->map->access = 0x0;
+
+ for (i = 0; i < IPCIDX_MAX; i++) {
+ struct ringbuf *r = &si->rb[i];
+ struct ringbuf_info *info = &rb_info[i];
+ struct ringbuf_cont *cont = &si->map->rbcont[i];
+
+ r->out_base = base + info->out_off;
+ r->in_base = base + info->in_off;
+ r->info = info;
+ r->cont = cont;
+
+ cont->out_head = 0;
+ cont->out_tail = 0;
+ cont->in_head = 0;
+ cont->in_tail = 0;
+ }
+}
+
+static void _init_proc(struct sipc *si)
+{
+ u32 mailbox;
+ int r;
+
+ dev_dbg(&si->svndev->dev, "%s\n", __func__);
+ r = onedram_read_mailbox(&mailbox);
+ if (r)
+ return;
+
+ mailbox = 0xc8;
+ sipc_handler(mailbox, si);
+}
+
+struct sipc *sipc_open(void (*queue)(u32, void*), struct net_device *ndev)
+{
+ struct sipc *si;
+ struct resource *res;
+ int r;
+ void *onedram_vbase;
+
+ if (!queue || !ndev)
+ return ERR_PTR(-EINVAL);
+
+ si = kzalloc(sizeof(struct sipc), GFP_KERNEL);
+ if (!si)
+ return ERR_PTR(-ENOMEM);
+
+ /* If FMT_SZ grown up, MUST be changed!! */
+ si->frag_buf = vmalloc(FMT_SZ);
+ memset(si->frag_buf, 0x00, FMT_SZ);
+ if (!si->frag_buf) {
+ sipc_close(&si);
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&si->frag_map.head);
+
+ res = onedram_request_region(0, SIPC_MAP_SIZE, SIPC_NAME);
+ if (!res) {
+ sipc_close(&si);
+ return ERR_PTR(-EBUSY);
+ }
+ si->res = res;
+
+ r = onedram_register_handler(sipc_handler, si);
+ if (r) {
+ sipc_close(&si);
+ return ERR_PTR(r);
+ }
+ si->queue = queue;
+ si->queue_data = ndev;
+ si->svndev = ndev;
+
+ /* TODO: need?? */
+ if (work_pending(&pdp_work))
+ flush_work(&pdp_work);
+
+ r = sysfs_create_group(&si->svndev->dev.kobj, &pdp_group);
+ if (r) {
+ sipc_close(&si);
+ return ERR_PTR(r);
+ }
+ si->group = &pdp_group;
+
+#if defined(NOISY_DEBUG)
+ _dev = &si->svndev->dev;
+#endif
+
+ onedram_get_vbase(&onedram_vbase);
+
+ if (onedram_vbase)
+ _init_data(si, (unsigned char *)onedram_vbase);
+ else
+ _init_data(si, (unsigned char *)res->start);
+
+ skb_queue_head_init(&si->rfs_rx);
+
+ /* process init message */
+ _init_proc(si);
+
+ dev_dbg(&si->svndev->dev, "sipc_open Done.\n");
+
+ return si;
+}
+
+static void clear_pdp_wq(struct work_struct *work)
+{
+ int i;
+
+ mutex_lock(&pdp_mutex);
+
+ for (i = 0; i < sizeof(pdp_devs)/sizeof(pdp_devs[0]); i++) {
+ if (pdp_devs[i]) {
+ destroy_pdp(&pdp_devs[i]);
+ clear_bit(i, pdp_bitmap);
+ }
+ }
+ pdp_cnt = 0;
+
+ mutex_unlock(&pdp_mutex);
+}
+
+void sipc_exit(void)
+{
+ if (work_pending(&pdp_work))
+ flush_work(&pdp_work);
+ else
+ clear_pdp_wq(NULL);
+}
+
+void sipc_close(struct sipc **psi)
+{
+ struct sipc *si;
+
+ if (!psi || !*psi)
+ return;
+
+ si = *psi;
+
+ if (si->group && si->svndev) {
+ int i;
+ sysfs_remove_group(&si->svndev->dev.kobj, si->group);
+
+ mutex_lock(&pdp_mutex);
+ for (i = 0; i < sizeof(pdp_devs)/sizeof(pdp_devs[0]); i++) {
+ if (pdp_devs[i])
+ netif_stop_queue(pdp_devs[i]);
+ }
+ mutex_unlock(&pdp_mutex);
+ schedule_work(&pdp_work);
+ }
+
+ if (si->frag_buf)
+ vfree(si->frag_buf);
+
+ if (si->queue)
+ onedram_unregister_handler(sipc_handler);
+
+ if (si->res)
+ onedram_release_region(0, SIPC_MAP_SIZE);
+
+ kfree(si);
+ *psi = NULL;
+}
+
+static inline void _wake_queue(int idx)
+{
+ mutex_lock(&pdp_mutex);
+
+ if (pdp_devs[idx] && !test_bit(idx, pdp_bitmap))
+ netif_wake_queue(pdp_devs[idx]);
+
+ mutex_unlock(&pdp_mutex);
+}
+
+static int __write(struct ringbuf *rb, u8 *buf, unsigned int size)
+{
+ int c;
+ int len = 0;
+
+ if (!cp_state) {
+ printk(KERN_ERR "__write : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ _dbg("%s b: size %u head %u tail %u\n", __func__,
+ size, rb->cont->out_head, rb->cont->out_tail);
+ _dbg_dump(buf, size);
+
+ while (1) {
+ c = CIRC_SPACE_TO_END(rb->cont->out_head,
+ rb->cont->out_tail, rb->info->size);
+ if (size < c)
+ c = size;
+ if (c <= 0)
+ break;
+ memcpy(rb->out_base + rb->cont->out_head, buf, c);
+ rb->cont->out_head = (rb->cont->out_head + c)
+ & (rb->info->size - 1);
+ buf += c;
+ size -= c;
+ len += c;
+ }
+
+ _dbg("%s a: size %u head %u tail %u\n", __func__,
+ len, rb->cont->out_head, rb->cont->out_tail);
+
+ return len;
+}
+
+static inline void _set_raw_hdr(struct raw_hdr *h, int res,
+ unsigned int len, int control)
+{
+ h->len = len;
+ h->channel = CHID(res);
+ h->control = 0;
+}
+
+static int _write_raw_buf(struct ringbuf *rb, int res, struct sk_buff *skb)
+{
+ int len;
+ struct raw_hdr h;
+
+ _dbg("%s: packet %p res 0x%02x\n", __func__, skb, res);
+
+ len = skb->len + sizeof(h);
+
+ _set_raw_hdr(&h, res, len, 0);
+
+ len = __write(rb, (u8 *)hdlc_start, sizeof(hdlc_start));
+ len += __write(rb, (u8 *)&h, sizeof(h));
+ len += __write(rb, skb->data, skb->len);
+ len += __write(rb, (u8 *)hdlc_end, sizeof(hdlc_end));
+
+ return len;
+}
+
+static int _write_raw_skb(struct ringbuf *rb, int res, struct sk_buff *skb)
+{
+ char *b;
+
+ if (!cp_state) {
+ printk(KERN_ERR "_write_raw_skb : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ _dbg("%s: packet %p res 0x%02x\n", __func__, skb, res);
+
+ b = skb_put(skb, sizeof(hdlc_end));
+ memcpy(b, hdlc_end, sizeof(hdlc_end));
+
+ b = skb_push(skb, sizeof(struct raw_hdr) + sizeof(hdlc_start));
+ memcpy(b, hdlc_start, sizeof(hdlc_start));
+
+ b += sizeof(hdlc_start);
+
+ _set_raw_hdr((struct raw_hdr *)b, res,
+ skb->len - sizeof(hdlc_start) - sizeof(hdlc_end), 0);
+
+ return __write(rb, skb->data, skb->len);
+}
+
+static int _write_raw(struct ringbuf *rb, struct sk_buff *skb, int res)
+{
+ int len;
+ int space;
+
+ space = CIRC_SPACE(rb->cont->out_head,
+ rb->cont->out_tail, rb->info->size);
+ if (space < skb->len + sizeof(struct raw_hdr)
+ + sizeof(hdlc_start) + sizeof(hdlc_end))
+ return -ENOSPC;
+ mutex_lock(&pdp_mutex);
+ if (skb_headroom(skb) > (sizeof(struct raw_hdr) + sizeof(hdlc_start))
+ && skb_tailroom(skb) > sizeof(hdlc_end)) {
+ len = _write_raw_skb(rb, res, skb);
+ } else {
+ len = _write_raw_buf(rb, res, skb);
+ }
+ mutex_unlock(&pdp_mutex);
+ if (res >= PN_PDP_START && res <= PN_PDP_END)
+ _wake_queue(PDP_ID(res));
+ else
+ netif_wake_queue(skb->dev);
+ return len;
+}
+
+static int _write_rfs_buf(struct ringbuf *rb, struct sk_buff *skb)
+{
+ int len;
+
+ _dbg("%s: packet %p\n", __func__, skb);
+ len = __write(rb, (u8 *)hdlc_start, sizeof(hdlc_start));
+ len += __write(rb, skb->data, skb->len);
+ len += __write(rb, (u8 *)hdlc_end, sizeof(hdlc_end));
+
+ return len;
+}
+
+static int _write_rfs_skb(struct ringbuf *rb, struct sk_buff *skb)
+{
+ char *b;
+
+ if (!cp_state) {
+ printk(KERN_ERR "_write_rfs_skb : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ _dbg("%s: packet %p\n", __func__, skb);
+ b = skb_put(skb, sizeof(hdlc_end));
+ memcpy(b, hdlc_end, sizeof(hdlc_end));
+
+ b = skb_push(skb, sizeof(hdlc_start));
+ memcpy(b, hdlc_start, sizeof(hdlc_start));
+
+ return __write(rb, skb->data, skb->len);
+}
+
+static int _write_rfs(struct ringbuf *rb, struct sk_buff *skb)
+{
+ int len;
+ int space;
+
+ space = CIRC_SPACE(rb->cont->out_head,
+ rb->cont->out_tail, rb->info->size);
+ if (space < skb->len + sizeof(hdlc_start) + sizeof(hdlc_end))
+ return -ENOSPC;
+
+ if (skb_headroom(skb) > sizeof(hdlc_start)
+ && skb_tailroom(skb) > sizeof(hdlc_end)) {
+ len = _write_rfs_skb(rb, skb);
+ } else {
+ len = _write_rfs_buf(rb, skb);
+ }
+
+ netif_wake_queue(skb->dev);
+ return len;
+}
+
+static int _write_fmt_buf(char *frag_buf, struct ringbuf *rb,
+ struct sk_buff *skb, struct frag_info *fi, int wlen,
+ u8 control)
+{
+ char *buf = frag_buf;
+ struct fmt_hdr *h;
+
+ if (!cp_state) {
+ printk(KERN_ERR "_write_fmt_buf : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ memcpy(buf, hdlc_start, sizeof(hdlc_start));
+ buf += sizeof(hdlc_start);
+
+ h = (struct fmt_hdr *)buf;
+ h->len = sizeof(struct fmt_hdr) + wlen;
+ h->control = control;
+ buf += sizeof(struct fmt_hdr);
+
+ memcpy(buf, skb->data + fi->offset, wlen);
+ buf += wlen;
+
+ memcpy(buf, hdlc_end, sizeof(hdlc_end));
+ buf += sizeof(hdlc_end);
+
+ return __write(rb, frag_buf, buf - frag_buf);
+}
+
+static int _write_fmt(struct sipc *si, struct ringbuf *rb, struct sk_buff *skb)
+{
+ int len;
+ int space;
+ int remain;
+ struct frag_info *fi = &si->frag;
+
+ if (skb != fi->skb) {
+ /* new packet */
+ fi->skb = skb;
+ fi->offset = 0;
+ }
+
+ len = 0;
+ remain = skb->len - fi->offset;
+
+ _dbg("%s: packet %p length %d sent %d\n",
+ __func__, skb, skb->len, fi->offset);
+
+ while (remain > 0) {
+ int wlen;
+ u8 control;
+
+ space = CIRC_SPACE(rb->cont->out_head,
+ rb->cont->out_tail, rb->info->size);
+ space -= sizeof(struct fmt_hdr)
+ + sizeof(hdlc_start) + sizeof(hdlc_end);
+ if (space < FMT_TX_MIN)
+ return -ENOSPC;
+
+ if (remain > space) {
+ /* multiple frame */
+ wlen = space;
+ control = 0x1 | FMT_MB_MASK;
+ } else {
+ wlen = remain;
+ if (fi->offset == 0) {
+ /* single frame */
+ control = 0x0;
+ } else {
+ /* last frmae */
+ control = 0x1;
+ }
+ }
+
+ wlen = _write_fmt_buf(si->frag_buf, rb, skb, fi, wlen, control);
+ if (wlen < 0)
+ return wlen;
+
+ len += wlen;
+
+ wlen -= sizeof(hdlc_start) + sizeof(struct fmt_hdr)
+ + sizeof(hdlc_end);
+
+ fi->offset += wlen;
+ remain -= wlen;
+ }
+
+ if (len > 0) {
+ fi->skb = NULL;
+ fi->offset = 0;
+ }
+
+ netif_wake_queue(skb->dev);
+ return len; /* total write bytes */
+}
+
+static int _write(struct sipc *si, int res, struct sk_buff *skb, u32 *mailbox)
+{
+ int r;
+ int rid;
+
+ rid = res_to_ridx(res);
+ if (rid < 0 || rid >= IPCIDX_MAX)
+ return -EINVAL;
+
+ switch (rid) {
+ case IPCIDX_FMT:
+ r = _write_fmt(si, &si->rb[rid], skb);
+ break;
+ case IPCIDX_RAW:
+ r = _write_raw(&si->rb[rid], skb, res);
+ break;
+ case IPCIDX_RFS:
+ r = _write_rfs(&si->rb[rid], skb);
+ break;
+ default:
+ /* do nothing */
+ r = 0;
+ break;
+ }
+
+ if (r > 0)
+ *mailbox |= mb_data[rid].mask_send;
+
+ _dbg("%s: return %d\n", __func__, r);
+ return r;
+}
+
+static inline void _update_stat(struct net_device *ndev, unsigned int len)
+{
+ if (!ndev)
+ return;
+
+ ndev->stats.tx_bytes += len;
+ ndev->stats.tx_packets++;
+}
+
+static inline int _write_pn(struct sipc *si, struct sk_buff *skb, u32 *mb)
+{
+ int r;
+ struct phonethdr *ph;
+
+ ph = pn_hdr(skb);
+ skb_pull(skb, sizeof(struct phonethdr) + 1);
+
+ r = _write(si, ph->pn_res, skb, mb);
+ if (r < 0)
+ skb_push(skb, sizeof(struct phonethdr) + 1);
+
+ return r;
+}
+
+int sipc_write(struct sipc *si, struct sk_buff_head *sbh)
+{
+ int r;
+ u32 mailbox;
+ struct sk_buff *skb;
+
+ if (!sbh)
+ return -EINVAL;
+
+ if (!si) {
+ skb_queue_purge(sbh);
+ return -ENXIO;
+ }
+
+ r = _get_auth();
+ if (r) {
+ if (factory_test_force_sleep) {
+ printk(KERN_ERR "tx ignored for factory force sleep\n");
+ skb_queue_purge(sbh);
+ return 0;
+ } else {
+ return r;
+ }
+ }
+
+ r = mailbox = 0;
+ skb = skb_dequeue(sbh);
+ while (skb) {
+ struct net_device *ndev = skb->dev;
+ int len = skb->len;
+
+ dev_dbg(&si->svndev->dev, "write packet %p\n", skb);
+
+ if (skb->protocol != __constant_htons(ETH_P_PHONET)) {
+ struct pdp_priv *priv;
+ priv = netdev_priv(ndev);
+ r = _write(si, PN_PDP(priv->channel), skb, &mailbox);
+ } else
+ r = _write_pn(si, skb, &mailbox);
+
+ if (r < 0)
+ break;
+
+ _update_stat(ndev, len);
+ dev_kfree_skb_any(skb);
+
+ skb = skb_dequeue(sbh);
+ }
+
+ _req_rel_auth(si);
+ _put_auth(si);
+
+ if (mailbox)
+ onedram_write_mailbox(MB_DATA(mailbox));
+
+ if (r < 0) {
+ if (r == -ENOSPC) {
+ dev_err(&si->svndev->dev,
+ "write nospc queue %p\n", skb);
+ skb_queue_head(sbh, skb);
+ netif_stop_queue(skb->dev);
+ } else {
+ dev_err(&si->svndev->dev,
+ "write err %d, drop %p\n", r, skb);
+ dev_kfree_skb_any(skb);
+ }
+ }
+
+ return r;
+}
+
+extern int __read(struct ringbuf *rb, unsigned char *buf, unsigned int size)
+{
+ int c;
+ int len = 0;
+ unsigned char *p = buf;
+
+ if (!cp_state) {
+ printk(KERN_ERR "__read : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ _dbg("%s b: size %u head %u tail %u\n", __func__,
+ size, rb->cont->in_head, rb->cont->in_tail);
+
+ while (1) {
+ c = CIRC_CNT_TO_END(rb->cont->in_head,
+ rb->cont->in_tail, rb->info->size);
+ if (size < c)
+ c = size;
+ if (c <= 0)
+ break;
+ if (p) {
+ memcpy(p, rb->in_base + rb->cont->in_tail, c);
+ p += c;
+ }
+ rb->cont->in_tail = (rb->cont->in_tail + c)
+ & (rb->info->size - 1);
+ size -= c;
+ len += c;
+ }
+
+ _dbg("%s a: size %u head %u tail %u\n", __func__,
+ len, rb->cont->in_head, rb->cont->in_tail);
+ _dbg_dump(buf, len);
+
+ return len;
+}
+
+static inline void _get_raw_hdr(struct raw_hdr *h, int *res,
+ unsigned int *len, int *control)
+{
+ if (res)
+ *res = PN_RAW(h->channel);
+ if (len)
+ *len = h->len;
+ if (control)
+ *control = h->control;
+}
+
+static inline void _phonet_rx(struct net_device *ndev,
+ struct sk_buff *skb, int res)
+{
+ int r;
+ struct phonethdr *ph;
+
+ skb->protocol = __constant_htons(ETH_P_PHONET);
+
+ ph = (struct phonethdr *)skb_push(skb, sizeof(struct phonethdr));
+ ph->pn_rdev = ndev->dev_addr[0];
+ ph->pn_sdev = 0;
+ ph->pn_res = res;
+ ph->pn_length = __cpu_to_be16(skb->len + 2 - sizeof(*ph));
+ ph->pn_robj = 0;
+ ph->pn_sobj = 0;
+
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += skb->len;
+
+ skb_reset_mac_header(skb);
+
+ r = netif_rx_ni(skb);
+ if (r != NET_RX_SUCCESS)
+ dev_err(&ndev->dev, "phonet rx error: %d\n", r);
+
+ _dbg("%s: res 0x%02x packet %p len %d\n", __func__, res, skb, skb->len);
+}
+
+static int _read_pn(struct net_device *ndev, struct ringbuf *rb, int len,
+ int res)
+{
+ int r;
+ struct sk_buff *skb;
+ char *p;
+ int read_len = len + sizeof(hdlc_end);
+
+ _dbg("%s: res 0x%02x data %d\n", __func__, res, len);
+
+ skb = netdev_alloc_skb(ndev, read_len + sizeof(struct phonethdr));
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ skb_reserve(skb, sizeof(struct phonethdr));
+
+ p = skb_put(skb, len);
+ r = __read(rb, p, read_len);
+ if (r != read_len) {
+ kfree_skb(skb);
+ return -EBADMSG;
+ }
+
+ _phonet_rx(ndev, skb, res);
+
+ return r;
+}
+
+static inline struct sk_buff *_alloc_phskb(struct net_device *ndev, int len)
+{
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb(ndev, len + sizeof(struct phonethdr));
+ if (likely(skb))
+ skb_reserve(skb, sizeof(struct phonethdr));
+
+ return skb;
+}
+
+static inline int _alloc_rfs(struct net_device *ndev,
+ struct sk_buff_head *list, int len)
+{
+ int r = 0;
+ struct sk_buff *skb;
+
+ __skb_queue_head_init(list);
+
+ while (len > 0) {
+ skb = _alloc_phskb(ndev, RFS_MTU);
+ if (unlikely(!skb)) {
+ r = -ENOMEM;
+ break;
+ }
+ __skb_queue_tail(list, skb);
+ len -= RFS_MTU;
+ }
+
+ return r;
+}
+static void _free_rfs(struct sk_buff_head *list)
+{
+ struct sk_buff *skb;
+
+ skb = __skb_dequeue(list);
+ while (skb) {
+ __kfree_skb(skb);
+ skb = __skb_dequeue(list);
+ }
+}
+
+static inline int _read_rfs_rb(struct ringbuf *rb, int len,
+ struct sk_buff_head *list)
+{
+ int r;
+ int read_len;
+ struct sk_buff *skb;
+ char *p;
+
+ read_len = 0;
+ skb = list->next;
+ while (skb != (struct sk_buff *)list) {
+ int rd = RFS_MTU;
+
+ if (skb == list->next) /* first sk has header */
+ rd -= sizeof(struct rfs_hdr);
+
+ if (len < rd)
+ rd = len;
+
+ p = skb_put(skb, rd);
+ r = __read(rb, p, rd);
+ if (r != rd)
+ return -EBADMSG;
+
+ len -= r;
+ read_len += r;
+ skb = skb->next;
+ }
+
+ return read_len;
+}
+
+static int _read_rfs_data(struct sipc *si, struct ringbuf *rb, int len,
+ struct rfs_hdr *h)
+{
+ int r;
+ struct sk_buff_head list;
+ struct sk_buff *skb;
+ char *p;
+ int read_len;
+ struct net_device *ndev = si->svndev;
+
+ if (!cp_state) {
+ printk(KERN_ERR "_read_rfs_data : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ _dbg("%s: %d bytes\n", __func__, len);
+
+ /* alloc sk_buffs */
+ r = _alloc_rfs(ndev, &list, len + sizeof(struct rfs_hdr));
+ if (r)
+ goto free_skb;
+
+ skb = list.next;
+ p = skb_put(skb, sizeof(struct rfs_hdr));
+ memcpy(p, h, sizeof(struct rfs_hdr));
+
+ /* read data all */
+ r = _read_rfs_rb(rb, len, &list);
+ if (r < 0)
+ goto free_skb;
+
+ read_len = r;
+
+ /* move to rfs_rx queue */
+ skb = __skb_dequeue(&list);
+ while (skb) {
+ skb_queue_tail(&si->rfs_rx, skb);
+ skb = __skb_dequeue(&list);
+ }
+
+ /* remove hdlc_end */
+ read_len += __read(rb, NULL, sizeof(hdlc_end));
+
+ return read_len;
+
+free_skb:
+ _free_rfs(&list);
+ return r;
+}
+
+static int _read_pdp(struct ringbuf *rb, int len,
+ int res)
+{
+ int r;
+ struct sk_buff *skb;
+ char *p;
+ int read_len = len + sizeof(hdlc_end);
+ struct net_device *ndev;
+
+ _dbg("%s: res 0x%02x data %d\n", __func__, res, len);
+
+ mutex_lock(&pdp_mutex);
+
+ ndev = pdp_devs[PDP_ID(res)];
+ if (!ndev) {
+ /* drop data */
+ r = __read(rb, NULL, read_len);
+ mutex_unlock(&pdp_mutex);
+ return r;
+ }
+
+ skb = netdev_alloc_skb(ndev, read_len);
+ if (unlikely(!skb)) {
+ mutex_unlock(&pdp_mutex);
+ return -ENOMEM;
+ }
+
+ p = skb_put(skb, len);
+ r = __read(rb, p, read_len);
+ if (r != read_len) {
+ mutex_unlock(&pdp_mutex);
+ kfree_skb(skb);
+ return -EBADMSG;
+ }
+ ndev->stats.rx_packets++;
+ ndev->stats.rx_bytes += skb->len;
+
+ mutex_unlock(&pdp_mutex);
+
+ read_len = r;
+
+ skb->protocol = __constant_htons(ETH_P_IP);
+
+ skb_reset_mac_header(skb);
+
+ _dbg("%s: pdp packet %p len %d\n", __func__, skb, skb->len);
+
+ r = netif_rx_ni(skb);
+ if (r != NET_RX_SUCCESS)
+ dev_err(&ndev->dev, "pdp rx error: %d\n", r);
+
+ return read_len;
+}
+
+static int _read_raw(struct sipc *si, int inbuf, struct ringbuf *rb)
+{
+ int r;
+ char buf[sizeof(struct raw_hdr) + sizeof(hdlc_start)];
+ int res, data_len;
+ u32 tail;
+
+ while (inbuf > 0) {
+ tail = rb->cont->in_tail;
+
+ r = __read(rb, buf, sizeof(buf));
+ if (r < sizeof(buf) ||
+ strncmp(buf, hdlc_start, sizeof(hdlc_start))) {
+ dev_err(&si->svndev->dev, "Bad message: %c %d\n",
+ buf[0], r);
+ return -EBADMSG;
+ }
+ inbuf -= r;
+
+ _get_raw_hdr((struct raw_hdr *)&buf[sizeof(hdlc_start)],
+ &res, &data_len, NULL);
+
+ data_len -= sizeof(struct raw_hdr);
+
+ if (res >= PN_PDP_START && res <= PN_PDP_END)
+ r = _read_pdp(rb, data_len, res);
+ else
+ r = _read_pn(si->svndev, rb, data_len, res);
+
+ if (r < 0) {
+ if (r == -ENOMEM)
+ rb->cont->in_tail = tail;
+
+ return r;
+ }
+
+ inbuf -= r;
+ }
+
+ return 0;
+}
+
+static int _read_rfs(struct sipc *si, int inbuf, struct ringbuf *rb)
+{
+ int r;
+ char buf[sizeof(struct rfs_hdr) + sizeof(hdlc_start)];
+ int data_len;
+ u32 tail;
+ struct rfs_hdr *h;
+
+ h = (struct rfs_hdr *)&buf[sizeof(hdlc_start)];
+ while (inbuf > 0) {
+ tail = rb->cont->in_tail;
+
+ r = __read(rb, buf, sizeof(buf));
+ if (r < sizeof(buf) ||
+ strncmp(buf, hdlc_start, sizeof(hdlc_start))) {
+ dev_err(&si->svndev->dev, "Bad message: %c %d\n",
+ buf[0], r);
+ return -EBADMSG;
+ }
+ inbuf -= r;
+
+ data_len = h->len - sizeof(struct rfs_hdr);
+
+ r = _read_rfs_data(si, rb, data_len, h);
+ if (r < 0) {
+ if (r == -ENOMEM)
+ rb->cont->in_tail = tail;
+
+ return r;
+ }
+
+ inbuf -= r;
+ }
+
+ return 0;
+}
+
+
+static struct frag_list *_find_frag_list(u8 control, struct frag_head *fh)
+{
+ struct frag_list *fl;
+ u8 msg_id = control & FMT_ID_MASK;
+
+ if (!test_bit(msg_id, fh->bitmap))
+ return NULL;
+
+ list_for_each_entry(fl, &fh->head, list) {
+ if (fl->msg_id == msg_id)
+ break;
+ }
+
+ return fl;
+}
+
+static int _fill_skb(struct sk_buff *skb, struct frag_list *fl)
+{
+ struct frag_block *fb, *n;
+ int offset = 0;
+ char *p;
+
+ if (!cp_state) {
+ printk(KERN_ERR "_fill_skb : cp_state : %d\n", cp_state);
+ return -EPERM;
+ }
+
+ list_for_each_entry_safe(fb, n, &fl->block_head, list) {
+ p = skb_put(skb, fb->len);
+ memcpy(p, fb->buf, fb->len);
+ offset += fb->len;
+ list_del(&fb->list);
+ kfree(fb);
+ }
+
+ return offset;
+}
+
+static void _destroy_frag_list(struct frag_list *fl, struct frag_head *fh)
+{
+ struct frag_block *fb, *n;
+
+ if (!fl || !fh)
+ return;
+
+ list_for_each_entry_safe(fb, n, &fl->block_head, list) {
+ kfree(fb);
+ }
+
+ clear_bit(fl->msg_id, fh->bitmap);
+ list_del(&fl->list);
+ kfree(fl);
+}
+
+static struct frag_list *_create_frag_list(u8 control, struct frag_head *fh)
+{
+ struct frag_list *fl;
+ u8 msg_id = control & FMT_ID_MASK;
+
+ if (test_bit(msg_id, fh->bitmap)) {
+ fl = _find_frag_list(control, fh);
+ _destroy_frag_list(fl, fh);
+ }
+
+ fl = kmalloc(sizeof(struct frag_list), GFP_KERNEL);
+ if (!fl)
+ return NULL;
+
+ INIT_LIST_HEAD(&fl->block_head);
+ fl->msg_id = msg_id;
+ fl->len = 0;
+ list_add(&fl->list, &fh->head);
+ set_bit(msg_id, fh->bitmap);
+
+ return fl;
+}
+
+static inline struct frag_block *_create_frag_block(struct frag_list *fl)
+{
+ struct frag_block *fb;
+
+ fb = kmalloc(sizeof(struct frag_block), GFP_KERNEL);
+ if (!fb)
+ return NULL;
+
+ fb->len = 0;
+ fb->ptr = fb->buf;
+ list_add_tail(&fb->list, &fl->block_head);
+
+ return fb;
+}
+
+static struct frag_block *_prepare_frag_block(struct frag_list *fl, int size)
+{
+ struct frag_block *fb;
+
+ if (size > FRAG_BLOCK_MAX)
+ BUG();
+
+ if (list_empty(&fl->block_head)) {
+ fb = _create_frag_block(fl);
+ } else {
+ fb = list_entry(fl->block_head.prev, struct frag_block, list);
+ if (size > FRAG_BLOCK_MAX - fb->len)
+ fb = _create_frag_block(fl);
+ }
+
+ return fb;
+}
+
+static int _read_fmt_frag(struct frag_head *fh, struct fmt_hdr *h,
+ struct ringbuf *rb)
+{
+ int r;
+ int data_len;
+ int read_len;
+ struct frag_list *fl;
+ struct frag_block *fb;
+
+ data_len = h->len - sizeof(struct fmt_hdr);
+ read_len = data_len + sizeof(hdlc_end);
+
+ _dbg("%s: data %d\n", __func__, data_len);
+
+ fl = _find_frag_list(h->control, fh);
+ if (!fl)
+ fl = _create_frag_list(h->control, fh);
+
+ if (!fl)
+ return -ENOMEM;
+
+ fb = _prepare_frag_block(fl, read_len);
+ if (!fb) {
+ if (fl->len == 0)
+ _destroy_frag_list(fl, fh);
+
+ return -ENOMEM;
+ }
+
+ r = __read(rb, fb->ptr, read_len);
+ if (r != read_len) {
+ _destroy_frag_list(fl, fh);
+ return -EBADMSG;
+ }
+
+ fb->ptr += data_len;
+ fb->len += data_len;
+ fl->len += data_len;
+
+ _dbg("%s: fl %p len %d fb %p ptr %p len %d\n", __func__,
+ fl, fl->len, fb, fb->ptr, fb->len);
+
+ return r;
+}
+
+static int _read_fmt_last(struct frag_head *fh, struct fmt_hdr *h,
+ struct ringbuf *rb, struct net_device *ndev)
+{
+ int r;
+ int data_len;
+ int read_len;
+ int total_len;
+ struct sk_buff *skb;
+ struct frag_list *fl;
+ char *p;
+
+ total_len = data_len = h->len - sizeof(struct fmt_hdr);
+ read_len = data_len + sizeof(hdlc_end);
+
+ fl = _find_frag_list(h->control & FMT_ID_MASK, fh);
+ if (fl)
+ total_len += fl->len;
+
+ _dbg("%s: total %d data %d\n", __func__, total_len, data_len);
+
+ skb = netdev_alloc_skb(ndev, total_len
+ + sizeof(struct phonethdr) + sizeof(hdlc_end));
+ if (unlikely(!skb))
+ return -ENOMEM;
+
+ skb_reserve(skb, sizeof(struct phonethdr));
+
+ if (fl)
+ _fill_skb(skb, fl);
+
+ _destroy_frag_list(fl, fh);
+
+ p = skb_put(skb, data_len);
+ r = __read(rb, p, read_len);
+ if (r != read_len) {
+ kfree_skb(skb);
+ return -EBADMSG;
+ }
+
+ _phonet_rx(ndev, skb, PN_FMT);
+
+ return r;
+}
+
+static int _read_fmt(struct sipc *si, int inbuf, struct ringbuf *rb)
+{
+ int r;
+ char buf[sizeof(struct fmt_hdr) + sizeof(hdlc_start)];
+ struct fmt_hdr *h;
+ u32 tail;
+ struct net_device *ndev = si->svndev;
+
+ h = (struct fmt_hdr *)&buf[sizeof(hdlc_start)];
+ while (inbuf > 0) {
+ tail = rb->cont->in_tail;
+
+ r = __read(rb, buf, sizeof(buf));
+ if (r < sizeof(buf) ||
+ strncmp(buf, hdlc_start, sizeof(hdlc_start))) {
+ dev_err(&ndev->dev, "Bad message: %c %d\n", buf[0], r);
+ return -EBADMSG;
+ }
+ inbuf -= r;
+
+ if (is_fmt_last(h->control))
+ r = _read_fmt_last(&si->frag_map, h, rb, ndev);
+ else
+ r = _read_fmt_frag(&si->frag_map, h, rb);
+
+ if (r < 0) {
+ if (r == -ENOMEM)
+ rb->cont->in_tail = tail;
+
+ return r;
+ }
+
+ inbuf -= r;
+ }
+
+ return 0;
+}
+
+static inline int check_mailbox(u32 mailbox, int idx)
+{
+ return mailbox & mb_data[idx].mask_send;
+}
+
+static inline void purge_buffer(struct ringbuf *rb)
+{
+ rb->cont->in_tail = rb->cont->in_head;
+}
+
+int sipc_read(struct sipc *si, u32 mailbox, int *cond)
+{
+ int r = 0;
+ int i;
+ u32 res = 0;
+
+ if (!si)
+ return -EINVAL;
+
+ r = _get_auth();
+ if (r)
+ return r;
+
+ for (i = 0; i < IPCIDX_MAX; i++) {
+ int inbuf;
+ struct ringbuf *rb;
+
+/* if (!check_mailbox(mailbox, i))
+ continue; */
+
+ rb = &si->rb[i];
+ inbuf = CIRC_CNT(rb->cont->in_head,
+ rb->cont->in_tail, rb->info->size);
+ if (!inbuf)
+ continue;
+
+ if (i == IPCIDX_FMT)
+ _fmt_wakelock_timeout();
+ else
+ _non_fmt_wakelock_timeout();
+
+ _dbg("%s: %d bytes in %d\n", __func__, inbuf, i);
+
+ r = rb->info->read(si, inbuf, rb);
+ if (r < 0) {
+ if (r == -EBADMSG)
+ purge_buffer(rb);
+
+ dev_err(&si->svndev->dev, "read err %d\n", r);
+ break;
+ }
+
+ if (mailbox & mb_data[i].mask_req_ack)
+ res = mb_data[i].mask_res_ack;
+ }
+
+ _req_rel_auth(si);
+ _put_auth(si);
+
+ if (res)
+ onedram_write_mailbox(MB_DATA(res));
+
+ *cond = skb_queue_len(&si->rfs_rx);
+
+ return r;
+}
+
+int sipc_rx(struct sipc *si)
+{
+ int tx_cnt;
+ struct sk_buff *skb;
+
+ if (!si)
+ return -EINVAL;
+
+ if (skb_queue_len(&si->rfs_rx) == 0)
+ return 0;
+
+ tx_cnt = 0;
+ skb = skb_dequeue(&si->rfs_rx);
+ while (skb) {
+ _phonet_rx(si->svndev, skb, PN_RFS);
+ tx_cnt++;
+ if (tx_cnt > RFS_TX_RATE)
+ break;
+ skb = skb_dequeue(&si->rfs_rx);
+ }
+
+ return skb_queue_len(&si->rfs_rx);
+}
+
+static inline ssize_t _debug_show_buf(struct sipc *si, char *buf)
+{
+ int i;
+ int r;
+ int inbuf, outbuf;
+ char *p = buf;
+
+ r = _get_auth();
+ if (r) {
+ p += sprintf(p, "\nGet authority: timed out!\n");
+ return p - buf;
+ }
+
+ p += sprintf(p, "\nHeader info ---------\n");
+
+ for (i = 0; i < IPCIDX_MAX; i++) {
+ struct ringbuf *rb = &si->rb[i];
+ inbuf = CIRC_CNT(rb->cont->in_head,
+ rb->cont->in_tail, rb->info->size);
+ outbuf = CIRC_CNT(rb->cont->out_head,
+ rb->cont->out_tail, rb->info->size);
+ p += sprintf(p, "%d\tSize\t%8u\n\tIn\t%8u\t%8u\t%8u\n\tOut\t%8u\t%8u\t%8u\n",
+ i, rb->info->size,
+ rb->cont->in_head, rb->cont->in_tail, inbuf,
+ rb->cont->out_head, rb->cont->out_tail, outbuf);
+ }
+ _put_auth(si);
+
+ return p - buf;
+}
+
+static inline ssize_t _debug_show_pdp(struct sipc *si, char *buf)
+{
+ int i;
+ char *p = buf;
+
+ p += sprintf(p, "\nPDP count: %d\n", pdp_cnt);
+
+ mutex_lock(&pdp_mutex);
+ for (i = 0; i < sizeof(pdp_devs)/sizeof(pdp_devs[0]); i++) {
+ if (pdp_devs[i])
+ p += sprintf(p, "pdp%d: %d", i,
+ netif_queue_stopped(pdp_devs[i]));
+ }
+ mutex_unlock(&pdp_mutex);
+
+ return p - buf;
+}
+
+ssize_t sipc_debug_show(struct sipc *si, char *buf)
+{
+ char *p = buf;
+
+ if (!si || !buf)
+ return 0;
+
+ p += _debug_show_buf(si, p);
+
+ p += _debug_show_pdp(si, p);
+
+ p += sprintf(p, "\nDebug command -----------\n");
+ p += sprintf(p, "R0\tcopy FMT out to in\n");
+ p += sprintf(p, "R1\tcopy RAW out to in\n");
+ p += sprintf(p, "R2\tcopy RFS out to in\n");
+
+ return p - buf;
+}
+
+static void test_copy_buf(struct sipc *si, int idx)
+{
+ struct ringbuf *rb;
+
+ if (idx >= IPCIDX_MAX)
+ return;
+
+ if (!cp_state) {
+ printk(KERN_ERR "test_copy_buf : cp_state : %d\n", cp_state);
+ return;
+ }
+
+ rb = (struct ringbuf *)&si->rb[idx];
+
+ memcpy(rb->in_base, rb->out_base, rb->info->size);
+ rb->cont->in_head = rb->cont->out_head;
+ rb->cont->in_tail = rb->cont->out_tail;
+
+ rb->cont->out_tail = rb->cont->out_head;
+
+ if (si->queue)
+ si->queue(MB_DATA(mb_data[idx].mask_send), si->queue_data);
+}
+
+int sipc_debug(struct sipc *si, const char *buf)
+{
+ int r;
+
+ if (!si || !buf)
+ return -EINVAL;
+
+ r = _get_auth();
+ if (r)
+ return r;
+
+ switch (buf[0]) {
+ case 'R':
+ test_copy_buf(si, buf[1]-'0');
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+ _put_auth(si);
+
+ return 0;
+}
+
+int sipc_whitelist(struct sipc *si, const char *buf, size_t count)
+{
+ int r;
+ struct ringbuf *rb;
+
+ printk(KERN_ERR "[%s]\n", __func__);
+
+ if (factory_test_force_sleep) {
+ printk(KERN_ERR "[%s]factory test\n", __func__);
+ return count;
+ }
+
+ if (!si || !buf)
+ return -EINVAL;
+
+ r = _get_auth();
+ if (r)
+ return r;
+
+ rb = (struct ringbuf *)&si->rb[IPCIDX_FMT];
+
+ /* write direct full-established-packet to buf */
+ r = __write(rb, (u8 *) buf, (unsigned int)count);
+
+ _req_rel_auth(si);
+ _put_auth(si);
+
+ onedram_write_mailbox(MB_DATA(mb_data[IPCIDX_FMT].mask_send));
+ return r;
+}
+
+int sipc_check_skb(struct sipc *si, struct sk_buff *skb)
+{
+ struct phonethdr *ph;
+
+ ph = pn_hdr(skb);
+
+ if (ph->pn_res == PN_CMD)
+ return 1;
+
+ return 0;
+}
+
+int sipc_do_cmd(struct sipc *si, struct sk_buff *skb)
+{
+ if (!si)
+ return -EINVAL;
+
+ skb_pull(skb, sizeof(struct phonethdr) + 1);
+
+ if (!strncmp("PHONE_ON", skb->data, sizeof("PHONE_ON")))
+ return 0;
+
+ return 0;
+}
+
+static int pdp_activate(struct net_device *svndev, int channel)
+{
+ int idx;
+ struct net_device *ndev;
+
+ if (!svndev || channel < 1 || channel > PDP_MAX)
+ return -EINVAL;
+
+ idx = channel - 1; /* start from 0 */
+
+ mutex_lock(&pdp_mutex);
+
+ if (pdp_devs[idx]) {
+ mutex_unlock(&pdp_mutex);
+ return -EBUSY;
+ }
+
+ ndev = create_pdp(channel, svndev);
+ if (IS_ERR(ndev)) {
+ mutex_unlock(&pdp_mutex);
+ return PTR_ERR(ndev);
+ }
+
+ pdp_devs[idx] = ndev;
+ pdp_cnt++;
+
+ mutex_unlock(&pdp_mutex);
+
+ return 0;
+}
+
+static int pdp_deactivate(int channel)
+{
+ int idx;
+
+ if (channel < 1 || channel > PDP_MAX)
+ return -EINVAL;
+
+ idx = channel - 1; /* start from 0 */
+
+ mutex_lock(&pdp_mutex);
+
+ if (!pdp_devs[idx]) {
+ mutex_unlock(&pdp_mutex);
+ return -EBUSY;
+ }
+
+ destroy_pdp(&pdp_devs[idx]);
+ clear_bit(idx, pdp_bitmap);
+ pdp_cnt--;
+
+ mutex_unlock(&pdp_mutex);
+
+ return 0;
+}
+
+static ssize_t show_act(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ char *p = buf;
+
+ mutex_lock(&pdp_mutex);
+
+ for (i = 0; i < sizeof(pdp_devs)/sizeof(pdp_devs[0]); i++) {
+ if (pdp_devs[i])
+ p += sprintf(p, "%d\n", (i+1));
+ }
+
+ mutex_unlock(&pdp_mutex);
+
+ return p - buf;
+}
+
+static ssize_t show_deact(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ char *p = buf;
+
+ mutex_lock(&pdp_mutex);
+
+ for (i = 0; i < sizeof(pdp_devs)/sizeof(pdp_devs[0]); i++) {
+ if (!pdp_devs[i])
+ p += sprintf(p, "%d\n", (i+1));
+ }
+
+ mutex_unlock(&pdp_mutex);
+
+ return p - buf;
+}
+
+static ssize_t store_act(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int r;
+ unsigned long chan;
+ struct net_device *ndev = to_net_dev(d);
+
+ if (!ndev)
+ return count;
+
+ r = strict_strtoul(buf, 10, &chan);
+ if (!r)
+ r = pdp_activate(ndev, chan);
+
+ if (r) {
+ dev_err(&ndev->dev, "Failed to activate pdp "
+ " channel %lu: %d\n", chan, r);
+
+ /* lock for pdp_activate fail - jongmoon.suh */
+ return r;
+ }
+
+ return count;
+}
+
+static ssize_t store_deact(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int r;
+ unsigned long chan;
+ struct net_device *ndev = to_net_dev(d);
+
+ if (!ndev)
+ return count;
+
+ r = strict_strtoul(buf, 10, &chan);
+ if (!r)
+ r = pdp_deactivate(chan);
+
+ if (r)
+ dev_err(&ndev->dev, "Failed to deactivate pdp"
+ " channel %lu: %d\n", chan, r);
+
+ return count;
+}
+
+static ssize_t show_suspend(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ int i;
+ char *p = buf;
+
+ mutex_lock(&pdp_mutex);
+
+ for (i = 0; i < sizeof(pdp_devs)/sizeof(pdp_devs[0]); i++) {
+ if (test_bit(i, pdp_bitmap))
+ p += sprintf(p, "%d\n", (i+1));
+ }
+
+ mutex_unlock(&pdp_mutex);
+
+ return p - buf;
+}
+
+static ssize_t store_suspend(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int r;
+ unsigned long chan;
+ int id;
+
+ r = strict_strtoul(buf, 10, &chan);
+ if (r)
+ return count;
+
+ if (chan < 1 || chan > PDP_MAX)
+ return count;
+
+ id = chan - 1;
+
+ mutex_lock(&pdp_mutex);
+
+ set_bit(id, pdp_bitmap);
+
+ if (pdp_devs[id])
+ netif_stop_queue(pdp_devs[id]);
+
+ mutex_unlock(&pdp_mutex);
+
+ return count;
+}
+
+static ssize_t store_resume(struct device *d,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int r;
+ unsigned long chan;
+ int id;
+
+ r = strict_strtoul(buf, 10, &chan);
+ if (r)
+ return count;
+
+ if (chan < 1 || chan > PDP_MAX)
+ return count;
+
+ id = chan - 1;
+
+ mutex_lock(&pdp_mutex);
+
+ clear_bit(id, pdp_bitmap);
+
+ if (pdp_devs[id])
+ netif_wake_queue(pdp_devs[id]);
+
+ mutex_unlock(&pdp_mutex);
+
+ return count;
+}
+
+void sipc_ramdump(struct sipc *si)
+{
+#if defined(CONFIG_KERNEL_DEBUG_SEC)
+ /* silent reset at debug level low */
+ if (kernel_sec_get_debug_level() == KERNEL_SEC_DEBUG_LEVEL_LOW)
+ return;
+#endif
+ _go_dump(si);
+}
+
+#if defined(CONFIG_KERNEL_DEBUG_SEC)
+static void _go_dump(struct sipc *si)
+{
+ int r;
+ t_kernel_sec_mmu_info mmu_info;
+
+ memset(cp_errmsg, 0, sizeof(cp_errmsg));
+
+ r = _get_auth();
+ if (r)
+ strcpy(cp_errmsg, ERRMSG);
+ else {
+ char *p;
+ p = (char *)si->map + FATAL_DISP;
+ memcpy(cp_errmsg, p, sizeof(cp_errmsg));
+ }
+
+ printk(KERN_ERR "CP Dump Cause - %s\n", cp_errmsg);
+
+ kernel_sec_set_upload_magic_number();
+ kernel_sec_get_mmu_reg_dump(&mmu_info);
+ kernel_sec_set_upload_cause(UPLOAD_CAUSE_CP_ERROR_FATAL);
+ kernel_sec_hw_reset(false);
+
+}
+#endif
diff --git a/drivers/phone_svn/svnet/sipc4.h b/drivers/phone_svn/svnet/sipc4.h
new file mode 100644
index 0000000..40e6714
--- /dev/null
+++ b/drivers/phone_svn/svnet/sipc4.h
@@ -0,0 +1,267 @@
+/**
+ * SAMSUNG MODEM IPC header version 4
+ *
+ * Copyright (C) 2010 Samsung Electronics. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __SAMSUNG_IPC_V4_H__
+#define __SAMSUNG_IPC_V4_H__
+
+/* IPC4.1 NEW PARTITION MAP
+ * This map is seen by AP side
+
+ 0x00_0000 ===========================================
+ MAGIC(4)| ACCESS(4) | RESERVED(8)
+ 0x00_0010 -------------------------------------------
+ FMT_OUT_PTR | FMT_IN_PTR
+ HEAD(4) | TAIL(4) | HEAD(4) | TAIL(4)
+ 0x00_0020 -------------------------------------------
+ RAW_OUT_PTR | RAW_IN_PTR
+ HEAD(4) | TAIL(4) | HEAD(4) | TAIL(4)
+ 0x00_0030 -------------------------------------------
+ RFS_OUT_PTR | RFS_IN_PTR
+ HEAD(4) | TAIL(4) | HEAD(4) | TAIL(4)
+ 0x00_0040 -------------------------------------------
+ RESERVED (4KB - 64B)
+ 0x00_1000 -------------------------------------------
+ CP Fatal Display (160B)
+ 0x00_10A0 -------------------------------------------
+ RESERVED (1MB - 4kb-4kb-4kb - 160B)
+ 0x0F_E000 -------------------------------------------
+ Formatted Out (64KB)
+ 0x10_E000 -------------------------------------------
+ Formatted In (64KB)
+ 0x11_E000 ===========================================
+ Raw Out (1MB)
+ 0x21_E000 ===========================================
+ Raw In (1MB)
+ 0x31_E000 ===========================================
+ RemoteFS Out (1MB)
+ 0x41_E000 ===========================================
+ RemoteFS In (1MB)
+ 0x51_E000 ===========================================
+
+ 0xFF_FFFF ===========================================
+*/
+
+#if defined(CONFIG_PHONE_IPC_SPI)
+#define FMT_OUT 0x0FE000
+#define FMT_IN 0x10E000
+#define FMT_SZ 0x10000 /* 65536 bytes */
+
+#define RAW_OUT 0x11E000
+#define RAW_IN 0x21E000
+#define RAW_SZ 0x100000 /* 1 MB */
+
+#define RFS_OUT 0x31E000
+#define RFS_IN 0x41E000
+#define RFS_SZ 0x100000 /* 1 MB */
+#else
+#if defined(CONFIG_PHONE_IPC_HSI)
+#define FMT_OUT 0x0FE000
+#define FMT_IN 0x10E000
+#define FMT_SZ 0x10000 /* 65536 bytes */
+
+#define RAW_OUT 0x11E000
+#define RAW_IN 0x21E000
+#define RAW_SZ 0x100000 /* 1 MB */
+
+#define RFS_OUT 0x31E000
+#define RFS_IN 0x41E000
+#define RFS_SZ 0x100000 /* 1 MB */
+#endif
+#endif
+
+#define FATAL_DISP 0x001000
+#define FATAL_DISP_SZ 0xA0 /* 160 bytes */
+
+#define SIPC_MAP_SIZE (RFS_IN + RFS_SZ)
+#define SIPC_NAME "IPCv4.1"
+
+enum {
+ IPCIDX_FMT = 0,
+ IPCIDX_RAW,
+ IPCIDX_RFS,
+ IPCIDX_MAX
+};
+
+struct ringbuf_cont {
+ u32 out_head;
+ u32 out_tail;
+ u32 in_head;
+ u32 in_tail;
+};
+
+struct sipc_mapped { /* map to the onedram start addr */
+ u32 magic;
+ u32 access;
+ u32 reserved[2];
+
+ struct ringbuf_cont rbcont[IPCIDX_MAX];
+};
+
+
+#define PN_CMD 0x00
+#define PN_FMT 0x01
+#define PN_RFS 0x41
+#define PN_RAW(chid) (0x20 | (chid))
+#define CHID(x) ((x) & 0x1F)
+
+#define res_to_ridx(x) ((x) >> 5)
+
+/*
+ * IPC Frame Format
+ */
+#define HDLC_START 0x7F
+#define HDLC_END 0x7E
+
+/* Formatted IPC Frame */
+struct fmt_hdr {
+ u16 len;
+ u8 control;
+} __packed;
+
+#define FMT_ID_MASK 0x7F /* Information ID mask */
+#define FMT_ID_SIZE 0x80 /* = 128 ( 0 ~ 127 ) */
+#define FMT_MB_MASK 0x80 /* More bit mask */
+
+#define FMT_TX_MIN 5 /* ??? */
+
+#define is_fmt_last(x) (!((x) & FMT_MB_MASK))
+
+/* RAW IPC Frame */
+struct raw_hdr {
+ u32 len;
+ u8 channel;
+ u8 control;
+} __packed;
+
+
+/* RFS IPC Frame */
+struct rfs_hdr {
+ u32 len;
+ u8 cmd;
+ u8 id;
+} __packed;
+
+/*
+ * RAW frame channel ID
+ */
+enum {
+ CHID_0 = 0,
+ CHID_CSD_VT_DATA,
+ CHID_PDS_PVT_CONTROL,
+ CHID_PDS_VT_AUDIO,
+ CHID_PDS_VT_VIDEO,
+ CHID_5, /* 5 */
+ CHID_6,
+ CHID_CDMA_DATA,
+ CHID_PCM_DATA,
+ CHID_TRANSFER_SCREEN,
+ CHID_PSD_DATA1, /* 10 */
+ CHID_PSD_DATA2,
+ CHID_PSD_DATA3,
+ CHID_PSD_DATA4,
+ CHID_PSD_DATA5,
+ CHID_PSD_DATA6, /* 15 */
+ CHID_PSD_DATA7,
+ CHID_PSD_DATA8,
+ CHID_PSD_DATA9,
+ CHID_PSD_DATA10,
+ CHID_PSD_DATA11, /* 20 */
+ CHID_PSD_DATA12,
+ CHID_PSD_DATA13,
+ CHID_PSD_DATA14,
+ CHID_PSD_DATA15,
+ CHID_BT_DUN, /* 25 */
+ CHID_CIQ_BRIDGE_DATA,
+ CHID_27,
+ CHID_CP_LOG1,
+ CHID_CP_LOG2,
+ CHID_30, /* 30 */
+ CHID_31,
+ CHID_MAX
+};
+
+#define PDP_MAX 15
+#define PN_PDP_START PN_RAW(CHID_PSD_DATA1)
+#define PN_PDP_END PN_RAW(CHID_PSD_DATA15)
+
+#define PN_PDP(chid) (0x20 | ((chid) + CHID_PSD_DATA1 - 1))
+#define PDP_ID(res) ((res) - PN_PDP_START)
+
+
+/*
+ * IPC 4.0 Mailbox message definition
+ */
+#define MB_VALID 0x0080
+#define MB_COMMAND 0x0040
+
+#define MB_CMD(x) (MB_VALID | MB_COMMAND | x)
+#define MB_DATA(x) (MB_VALID | x)
+
+/*
+ * If not command
+ */
+#define MBD_SEND_FMT 0x0002
+#define MBD_SEND_RAW 0x0001
+#define MBD_SEND_RFS 0x0100
+#define MBD_REQ_ACK_FMT 0x0020
+#define MBD_REQ_ACK_RAW 0x0010
+#define MBD_REQ_ACK_RFS 0x0400
+#define MBD_RES_ACK_FMT 0x0008
+#define MBD_RES_ACK_RAW 0x0004
+#define MBD_RES_ACK_RFS 0x0200
+
+/*
+ * If command
+ */
+enum {
+ MBC_NONE = 0,
+ MBC_INIT_START,
+ MBC_INIT_END,
+ MBC_REQ_ACTIVE,
+ MBC_RES_ACTIVE,
+ MBC_TIME_SYNC,
+ MBC_POWER_OFF,
+ MBC_RESET,
+ MBC_PHONE_START,
+ MBC_ERR_DISPLAY,
+ MBC_POWER_SAVE,
+ MBC_NV_REBUILD,
+ MBC_EMER_DOWN,
+ MBC_REQ_SEM,
+ MBC_RES_SEM,
+ MBC_MAX
+};
+#define MBC_MASK 0xFF
+
+/* CMD_INIT_END extended bit */
+#define CP_BOOT_ONLINE 0x0000
+#define CP_BOOT_AIRPLANE 0x1000
+#define AP_OS_ANDROID 0x0100
+#define AP_OS_WINMOBILE 0x0200
+#define AP_OS_LINUX 0x0300
+#define AP_OS_SYMBIAN 0x0400
+
+/* CMD_PHONE_START extended bit */
+#define CP_QUALCOMM 0x0100
+#define CP_INFINEON 0x0200
+#define CP_BROADCOM 0x0300
+
+
+#endif /* __SAMSUNG_IPC_V4_H__ */