summaryrefslogtreecommitdiff
path: root/drivers/char/modem_interface
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/char/modem_interface
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/char/modem_interface')
-rw-r--r--drivers/char/modem_interface/Makefile15
-rw-r--r--drivers/char/modem_interface/boot_driver.c242
-rw-r--r--drivers/char/modem_interface/boot_protocol.c417
-rw-r--r--drivers/char/modem_interface/modem_buffer.c256
-rw-r--r--drivers/char/modem_interface/modem_buffer.h58
-rw-r--r--drivers/char/modem_interface/modem_gpio_drv.c358
-rw-r--r--drivers/char/modem_interface/modem_interface_driver.c1088
-rw-r--r--drivers/char/modem_interface/modem_interface_driver.h84
-rw-r--r--drivers/char/modem_interface/modem_sdio_drv.c50
-rw-r--r--drivers/char/modem_interface/modem_spi_drv.c124
-rw-r--r--drivers/char/modem_interface/normal_mode.c157
11 files changed, 2849 insertions, 0 deletions
diff --git a/drivers/char/modem_interface/Makefile b/drivers/char/modem_interface/Makefile
new file mode 100644
index 00000000..e2a21bdd
--- /dev/null
+++ b/drivers/char/modem_interface/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for DWC_otg Highspeed USB controller driver
+#
+
+#PWD := $(shell pwd)
+#PORTLIB := $(PWD)/../dwc_common_port
+
+ifeq ($(CONFIG_MODEM_INTF_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_MODEM_INTF) += modem_interface.o
+modem_interface-objs := boot_driver.o boot_protocol.o modem_buffer.o
+modem_interface-objs += normal_mode.o modem_gpio_drv.o
+modem_interface-objs += modem_sdio_drv.o modem_interface_driver.o
diff --git a/drivers/char/modem_interface/boot_driver.c b/drivers/char/modem_interface/boot_driver.c
new file mode 100644
index 00000000..4aac1ed9
--- /dev/null
+++ b/drivers/char/modem_interface/boot_driver.c
@@ -0,0 +1,242 @@
+/* linux/arch/arm/mach-sc8800g/boot_driver.c
+ *
+ * Common setup code for boot up MODEM
+ *
+ * Copyright (C) 2012 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <asm/uaccess.h>
+#include <mach/modem_interface.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/timer.h>
+#include <linux/mmc/sdio_channel.h>
+#include <linux/wakelock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+
+#define DLOADER_NAME "dloader"
+#define READ_BUFFER_SIZE (4096)
+#define WRITE_BUFFER_SIZE (33*1024)
+
+extern void sdio_ipc_enable(u8 is_enable);
+extern int modem_intf_send_bootcomp_message();
+struct dloader_dev{
+ enum MODEM_Mode_type mode;
+ int open_count;
+ atomic_t read_excl;
+ atomic_t write_excl;
+ char *read_buffer;
+ char *write_buffer;
+};
+static struct dloader_dev *dl_dev=NULL;
+static struct wake_lock dloader_wake_lock;
+static inline int dloader_lock(atomic_t *excl)
+{
+ if (atomic_inc_return(excl) == 1) {
+ return 0;
+ } else {
+ atomic_dec(excl);
+ return -1;
+ }
+}
+
+static inline void dloader_unlock(atomic_t *excl)
+{
+ atomic_dec(excl);
+}
+
+static int dloader_open(struct inode *inode,struct file *filp)
+{
+ int rval;
+ if (dl_dev==NULL) {
+ return -EIO;
+ }
+ if (dl_dev->open_count!=0) {
+ printk(KERN_INFO "dloader_open %d \n",dl_dev->open_count);
+ return -EBUSY;
+ }
+
+ dl_dev->read_buffer = kzalloc(READ_BUFFER_SIZE, GFP_KERNEL);
+ if (dl_dev->read_buffer == NULL) {
+ printk(KERN_INFO "DLoade_open fail(NO MEM) \n");
+ return -ENOMEM;
+ }
+ dl_dev->write_buffer = kzalloc(WRITE_BUFFER_SIZE+4, GFP_KERNEL);
+ if (dl_dev->write_buffer == NULL) {
+ kfree(dl_dev->read_buffer);
+ dl_dev->read_buffer = NULL;
+ printk(KERN_INFO "DLoade_open fail(NO MEM) \n");
+ return -ENOMEM;
+ }
+
+ if(modem_intf_open(MODEM_MODE_BOOT,0)< 0){
+ kfree(dl_dev->write_buffer);
+ dl_dev->write_buffer = NULL;
+ kfree(dl_dev->read_buffer);
+ dl_dev->read_buffer = NULL;
+ printk(KERN_INFO "modem_intf_open failed \n");
+ return -EBUSY;
+ }
+
+ dl_dev->open_count++;
+ wake_lock(&dloader_wake_lock);
+
+ dl_dev->mode = MODEM_MODE_BOOT;
+
+ printk(KERN_INFO "DLoader_open %d times: %d\n", dl_dev->open_count, rval);
+ return 0;
+}
+static int dloader_read(struct file *filp,char __user *buf,size_t count,loff_t *pos)
+{
+ int read_len=0;
+
+ if ((dl_dev==NULL)||(dl_dev->open_count!=1)) {
+ return -EIO;
+ }
+
+ if (dloader_lock(&dl_dev->read_excl))
+ return -EBUSY;
+
+ if(dl_dev->mode==MODEM_MODE_BOOT){
+ if(count > READ_BUFFER_SIZE)
+ count = READ_BUFFER_SIZE;
+ read_len = modem_intf_read(dl_dev->read_buffer,count,0);
+ if (read_len>0){
+ if (copy_to_user(buf,dl_dev->read_buffer,read_len)){
+ dloader_unlock(&dl_dev->read_excl);
+ return -EFAULT;
+ }
+ }
+ } else {
+
+ dloader_unlock(&dl_dev->read_excl);
+ return -EFAULT;
+ }
+
+ dloader_unlock(&dl_dev->read_excl);
+
+ return read_len;
+}
+
+static int dloader_write(struct file *filp, const char __user *buf,size_t count,loff_t *pos)
+{
+ if ((dl_dev==NULL)||(dl_dev->open_count!=1))
+ return -EIO;
+
+ if (dloader_lock(&dl_dev->write_excl))
+ return -EBUSY;
+
+ if (count > WRITE_BUFFER_SIZE ) {
+ dloader_unlock(&dl_dev->write_excl);
+ return -EINVAL;
+ }
+ pr_debug("dloader_write: mode = %d\n",dl_dev->mode);
+ if (dl_dev->mode==MODEM_MODE_BOOT) {
+ if (copy_from_user(dl_dev->write_buffer,buf,count )){
+ dloader_unlock(&dl_dev->write_excl);
+ return -EFAULT;
+ }
+ modem_intf_write(dl_dev->write_buffer,count,0);
+ } else {
+
+ dloader_unlock(&dl_dev->write_excl);
+ return -EFAULT;
+ }
+
+ dloader_unlock(&dl_dev->write_excl);
+
+ return count;
+}
+
+static int dloader_release(struct inode *inode,struct file *filp)
+{
+ printk(KERN_INFO "dloader_release time = 0x%x \n",jiffies);
+ kfree(dl_dev->read_buffer);
+ kfree(dl_dev->write_buffer);
+ dl_dev->read_buffer = NULL;
+ dl_dev->write_buffer = NULL;
+ wake_unlock(&dloader_wake_lock);
+ dl_dev->open_count--;
+ dl_dev->mode = MODEM_MODE_NORMAL;
+ modem_intf_send_bootcomp_message();
+
+ return 0;
+}
+
+int dloader_abort()
+{
+ printk(KERN_INFO "dloader_abort!\n");
+ dl_dev->mode = MODEM_MODE_NORMAL;
+
+ return 0;
+}
+
+
+static struct file_operations dloader_fops = {
+ .owner = THIS_MODULE,
+ .read = dloader_read,
+ .write = dloader_write,
+ .open = dloader_open,
+ .release = dloader_release,
+};
+static struct miscdevice dl_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DLOADER_NAME,
+ .fops = &dloader_fops,
+};
+static int __init init(void)
+{
+ struct dloader_dev *dev;
+ int err=0;
+ printk(KERN_INFO "dloader_init\n");
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+ dev->open_count = 0;
+
+ atomic_set(&dev->read_excl, 0);
+ atomic_set(&dev ->write_excl, 0);
+ dl_dev = dev;
+ wake_lock_init(&dloader_wake_lock,WAKE_LOCK_SUSPEND,"dloader_wake_lock");
+ err = misc_register(&dl_device);
+
+ if(err){
+ printk(KERN_INFO "cdev_add failed!!!\n");
+ kfree(dev);
+ }
+ return err;
+}
+static void __exit cleanup(void)
+{
+ misc_deregister(&dl_device);
+ kfree(dl_dev);
+ dl_dev = NULL;
+}
+module_init(init);
+module_exit(cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SPRD boot driver");
diff --git a/drivers/char/modem_interface/boot_protocol.c b/drivers/char/modem_interface/boot_protocol.c
new file mode 100644
index 00000000..ebb96a63
--- /dev/null
+++ b/drivers/char/modem_interface/boot_protocol.c
@@ -0,0 +1,417 @@
+/*
+ * kernel/driver/char/modem_interface/boot_protocol.c
+ *
+ * Generic modem boot protocol
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/irqflags.h>
+#include "modem_buffer.h"
+#include "modem_interface_driver.h"
+
+#define SETUP_PACKET_SIZE 8
+#define ACK_PACKET_SIZE 6
+typedef struct dl_setup_packet{
+ unsigned short data_packet_size;
+ unsigned short data_type;
+ unsigned short data_check_sum;
+ unsigned short setup_check_sum;
+} SETUP_PACKET_T;
+typedef enum MBUS_DL_status{
+ MBUS_DL_IDLE,
+ MBUS_DL_WAIT_REQ,
+ MBUS_DL_WAIT_RTS,
+ MBUS_DL_SETUP,
+ MBUS_DL_SETUP_COMP,
+ MBUS_DL_DATA,
+ MBUS_DL_DATA_COMP,
+ MBUS_DL_ACK
+}DL_STATUS_E;
+
+
+extern void modem_intf_ctrl_gpio_handle_boot(int status);
+extern int dloader_abort();
+
+char *boot_status_string(DL_STATUS_E status)
+{
+ switch(status){
+ case MBUS_DL_IDLE: return "DL_IDLE";
+ case MBUS_DL_WAIT_REQ: return "DL_WAIT_REQ";
+ case MBUS_DL_WAIT_RTS: return "DL_WAIT_RTS";
+ case MBUS_DL_SETUP: return "DL_SETUP";
+ case MBUS_DL_SETUP_COMP: return "DL_SETUP_COMP";
+ case MBUS_DL_DATA: return "DL_DATA";
+ case MBUS_DL_DATA_COMP: return "DL_DATA_COMP";
+ case MBUS_DL_ACK: return "DL_ACK";
+ default: break;
+ }
+ return "UNKNOWN status";
+}
+
+
+
+static void boot_idle(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ int send_bffer_index=0xFF;
+ switch(msg->type){
+ case MODEM_SLAVE_RTS:
+ device->status = (int)MBUS_DL_WAIT_REQ;
+ break;
+ case MODEM_TRANSFER_REQ:
+ send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if (send_bffer_index!= 0xFF) {
+ device->out_transfering = send_bffer_index;
+ device->status = (int)MBUS_DL_WAIT_RTS;
+ }
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+ }
+}
+static void boot_wait_request(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ int send_bffer_index=0xFF;
+ switch(msg->type){
+ case MODEM_TRANSFER_REQ:
+ send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if(send_bffer_index!= 0xFF){
+ device->out_transfering = send_bffer_index;
+ device->op->write(device->send_buffer.buffer[send_bffer_index].addr,SETUP_PACKET_SIZE);
+ device->status = (int)MBUS_DL_SETUP;
+ }
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ case MODEM_TRANSFER_END:
+ break;
+ default:
+ break;
+ }
+}
+static void boot_wait_RTS(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ int send_bffer_index=0xFF;
+ unsigned short *data;
+ switch(msg->type){
+ case MODEM_SLAVE_RTS:
+ if(device->out_transfering < 2){
+ send_bffer_index = device->out_transfering;
+ data = (unsigned short *)device->send_buffer.buffer[send_bffer_index].addr;
+ device->op->write((char *)data,SETUP_PACKET_SIZE);
+ device->status = (int)MBUS_DL_SETUP;
+ }
+ break;
+ case MODEM_TRANSFER_REQ:
+ device->out_transfer_pending = 1;
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+ }
+}
+static void boot_setup(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ int send_bffer_index=0xFF;
+ char *buffer;
+ int size;
+ switch(msg->type){
+ case MODEM_TRANSFER_END:
+ device->status = (int)MBUS_DL_SETUP_COMP;
+ break;
+ case MODEM_TRANSFER_REQ:
+ device->out_transfer_pending = 1;
+ break;
+ case MODEM_SLAVE_RTS:
+ if(device->out_transfering < 2){
+ send_bffer_index = device->out_transfering;
+ buffer = &device->send_buffer.buffer[send_bffer_index].addr[SETUP_PACKET_SIZE];
+ size = device->send_buffer.buffer[send_bffer_index].write_point;
+ if (size <= SETUP_PACKET_SIZE)
+ size = 12;
+ device->op->write(buffer,size - SETUP_PACKET_SIZE);
+ pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
+ device->out_transfering = 0xFF;
+ device->status = (int)MBUS_DL_DATA;
+ }
+ if(device->out_transfer_pending){
+ send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if(send_bffer_index!= 0xFF){
+ device->out_transfering = send_bffer_index;
+ size = device->send_buffer.buffer[send_bffer_index].write_point;
+ device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
+ }
+ device->out_transfer_pending = 0;
+ }
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+ }
+}
+
+static void boot_setup_comp(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ int send_bffer_index=0xFF;
+ char *buffer;
+ int size;
+
+ switch(msg->type){
+ case MODEM_SLAVE_RTS:
+ if(device->out_transfering < 2){
+ send_bffer_index = device->out_transfering;
+ buffer = &device->send_buffer.buffer[send_bffer_index].addr[SETUP_PACKET_SIZE];
+ size = device->send_buffer.buffer[send_bffer_index].write_point;
+ if (size <= SETUP_PACKET_SIZE)
+ size = 12;
+ device->op->write(buffer,size - SETUP_PACKET_SIZE);
+ device->status = (int)MBUS_DL_DATA;
+ if(device->out_transfer_pending){
+ pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
+ device->out_transfering = 0xFF;
+ send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if(send_bffer_index!= 0xFF){
+ device->out_transfering = send_bffer_index;
+ size = device->send_buffer.buffer[send_bffer_index].write_point;
+ device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
+ }
+ device->out_transfer_pending = 0;
+ }
+ }
+ break;
+ case MODEM_TRANSFER_REQ:
+ device->out_transfer_pending = 1;
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+
+ }
+}
+static void boot_data(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ unsigned short *data;
+ int send_bffer_index=0xFF;
+ char *buffer;
+ int size;
+ switch(msg->type){
+ case MODEM_TRANSFER_END:
+ if(device->out_transfering < 2){
+ pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
+ device->out_transfering = 0xFF;
+ device->status = (int)MBUS_DL_DATA_COMP;
+ }
+ break;
+ case MODEM_TRANSFER_REQ:
+ if(device->out_transfering < 2){
+ pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
+ device->out_transfering = 0xFF;
+ }
+ send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if(send_bffer_index!= 0xFF){
+ device->out_transfering = send_bffer_index;
+ size = device->send_buffer.buffer[send_bffer_index].write_point;
+ device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
+ }
+ break;
+ case MODEM_SLAVE_RTS:
+ pingpang_buffer_send_complete(&device->send_buffer,device->out_transfering);
+ device->op->read(device->recv_buffer.buffer[1].addr,8);
+ device->out_transfering = 0xFF;
+ data = (unsigned short *)device->recv_buffer.buffer[1].addr;
+ device->status = (int)MBUS_DL_ACK;
+ if(device->out_transfer_pending){
+ send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if(send_bffer_index!= 0xFF){
+ device->out_transfering = send_bffer_index;
+ size = device->send_buffer.buffer[send_bffer_index].write_point;
+ device->op->write(device->send_buffer.buffer[send_bffer_index].addr,size);
+ }
+ device->out_transfer_pending = 0;
+ }
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+ }
+}
+static void boot_data_comp(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ unsigned short *data;
+ switch(msg->type){
+ case MODEM_SLAVE_RTS:
+ device->op->read(device->recv_buffer.buffer[1].addr,8);
+ data = (unsigned short *)device->recv_buffer.buffer[1].addr;
+ device->status = (int)MBUS_DL_ACK;
+ break;
+ case MODEM_TRANSFER_REQ:
+ device->out_transfer_pending = 1;
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+ }
+}
+static void boot_ack(struct modem_message_node *msg,struct modem_intf_device *device)
+{
+ int send_bffer_index=0xFF;
+ unsigned short *data;
+
+ switch(msg->type){
+ case MODEM_TRANSFER_END:
+ save_to_receive_buffer(&device->recv_buffer,device->recv_buffer.buffer[1].addr,ACK_PACKET_SIZE);
+ if(device->out_transfer_pending){
+ device->out_transfer_pending = 0;
+ device->out_transfering = send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+ if(device->out_transfering!=0xff){
+ device->status = (int)MBUS_DL_WAIT_RTS;
+ break;
+ }
+ }
+ device->status = (int)MBUS_DL_IDLE;
+ break;
+ case MODEM_TRANSFER_REQ:
+ device->out_transfer_pending = 1;
+ break;
+ case MODEM_SLAVE_RTS:
+ data = (unsigned short *)device->recv_buffer.buffer[1].addr;
+ save_to_receive_buffer(&device->recv_buffer,data,ACK_PACKET_SIZE);
+ if(device->out_transfer_pending){
+ device->out_transfer_pending = 0;
+ device->out_transfering = send_bffer_index = pingpang_buffer_send(&device->send_buffer);
+
+ data = (unsigned short *)device->send_buffer.buffer[send_bffer_index].addr;
+ device->op->write((char *)data,SETUP_PACKET_SIZE);
+
+ device->status = (int)MBUS_DL_SETUP;
+ } else {
+ device->status = (int)MBUS_DL_WAIT_REQ;
+ }
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = (int)MBUS_DL_IDLE;
+ device->out_transfering = 0;
+ dloader_abort();
+ break;
+ default:
+ break;
+ }
+}
+extern unsigned long sprd_get_system_tick(void);
+extern void dloader_record_timestamp(unsigned long time);
+
+void boot_protocol_process_dl_messages(struct modem_intf_device *device,
+ struct modem_message_node *msg)
+{
+ DL_STATUS_E status;
+
+ status =(DL_STATUS_E) device->status;
+
+ switch(status){
+ case MBUS_DL_IDLE:
+ boot_idle(msg,device);
+ break;
+ case MBUS_DL_SETUP:
+ boot_setup(msg,device);
+ break;
+ case MBUS_DL_WAIT_REQ:
+ boot_wait_request(msg,device);
+ break;
+ case MBUS_DL_WAIT_RTS:
+ boot_wait_RTS(msg,device);
+ break;
+ case MBUS_DL_SETUP_COMP:
+ boot_setup_comp(msg,device);
+ break;
+ case MBUS_DL_DATA:
+ boot_data(msg,device);
+ break;
+ case MBUS_DL_DATA_COMP:
+ boot_data_comp(msg,device);
+ break;
+ case MBUS_DL_ACK:
+ boot_ack(msg,device);
+ break;
+ }
+}
+
+void boot_protocol(struct modem_message_node *msg)
+{
+ struct modem_intf_device *device;
+
+ if((msg == NULL)||(msg->parameter1==0))
+ return;
+
+ device = (struct modem_intf_device *)msg->parameter1;
+
+ printk(">>boot entry(%d,%d) status: %s message: %s \n",
+ device->out_transfer_pending,device->out_transfering,
+ boot_status_string((DL_STATUS_E )device->status),
+ modem_intf_msg_string(msg->type));
+
+ //filter messages
+ switch(msg->type){
+ case MODEM_CTRL_GPIO_CHG:
+ modem_intf_ctrl_gpio_handle_boot(msg->parameter2);
+ break;
+ case MODEM_USER_REQ:
+ //now, just ignore user req in boot mode
+ break;
+ case MODEM_BOOT_CMP:
+ modem_intf_set_mode(MODEM_MODE_BOOTCOMP, 0);
+ break;
+ default:
+ //all other messages
+ boot_protocol_process_dl_messages(device, msg);
+ break;
+ }
+
+}
diff --git a/drivers/char/modem_interface/modem_buffer.c b/drivers/char/modem_interface/modem_buffer.c
new file mode 100644
index 00000000..e42a5a74
--- /dev/null
+++ b/drivers/char/modem_interface/modem_buffer.c
@@ -0,0 +1,256 @@
+/*
+ * kernel/driver/char/modem_interface/modem_buffer.c
+ *
+ * Generic modem interface pingpang buffer API.
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+/* #define DEBUG */
+/* #define VERBOSE_DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <mach/modem_interface.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/semaphore.h>
+#include <linux/irqflags.h>
+#include "modem_buffer.h"
+#define dloader_record_timestamp(time)
+
+spinlock_t buffer_lock;
+static int buffer_data_size(struct single_buffer_t *buffer)
+{
+ int data_size = 0;
+ if (buffer->write_point == buffer->read_point)
+ return 0;
+ data_size = buffer->write_point - buffer->read_point;
+ if (buffer->write_point < buffer->read_point)
+ data_size = buffer->size + data_size;
+ return data_size;
+}
+
+int save_to_receive_buffer(struct modem_buffer *buffer,char *data,int size)
+{
+ int free_space = 0;
+ int data_size = 0;
+ int i;
+ int write_point= buffer->buffer[0].write_point;
+
+ if (buffer->type==BUF_RECV) {
+ do{
+ data_size = buffer_data_size(&buffer->buffer[0]);
+ free_space = buffer->buffer[0].size-1-data_size;
+ if (free_space >= size)
+ break;
+ down(&buffer->buf_read_sem);
+ }while(1);
+ for(i=0;i<size;i++){
+ buffer->buffer[0].addr[write_point++]=data[i];
+ if(write_point >= buffer->buffer[0].size)
+ write_point = 0;
+ }
+ buffer->buffer[0].write_point = write_point;
+ up(&buffer->buf_read_sem);
+ return size;
+ }
+ return 0;
+}
+
+int pingpang_buffer_read(struct modem_buffer *buffer,char *data,int size)
+{
+ int read_len = 0;
+ int data_size = 0;
+ int i;
+ int read_point= buffer->buffer[0].read_point;
+
+ if (buffer->type==BUF_RECV) {
+ do{
+ if (buffer->buffer[0].write_point != buffer->buffer[0].read_point)
+ break;
+ down(&buffer->buf_read_sem);
+ }while(1);
+ data_size = buffer_data_size(&buffer->buffer[0]);
+ if(data_size==0)
+ return 0;
+
+ if(data_size < size){
+ read_len = data_size;
+ } else {
+ read_len = size;
+ }
+ for (i=0;i<read_len;i++) {
+ data[i]= buffer->buffer[0].addr[read_point++];
+ if(read_point >= buffer->buffer[0].size)
+ read_point = 0;
+ }
+ dloader_record_timestamp(0x30000000|buffer->buffer[0].read_point);
+ dloader_record_timestamp(0x40000000|read_point);
+ buffer->buffer[0].read_point = read_point;
+ up(&buffer->buf_read_sem);
+ return read_len;
+ }
+ return 0;
+}
+
+int pingpang_buffer_send(struct modem_buffer *buffer)
+{
+ enum BUF_status_t status;
+ int i,index;
+ unsigned long flags;
+
+ if(buffer->type == BUF_SEND){
+ if(buffer->trans_index!=0xFF)
+ index = buffer->trans_index;
+ else
+ index = buffer->save_index;
+ local_irq_save(flags);
+ spin_lock_irqsave(&buffer_lock, flags);
+ for(i=0;i<2;i++){
+ status = buffer->buffer[index].status;
+ if ((status != BUF_STATUS_IDLE) && (status != BUF_STATUS_WRITTEN)) {
+ buffer->buffer[index].status = BUF_STATUS_SENT;
+ local_irq_restore(flags);
+ spin_unlock_irqrestore(&buffer_lock, flags);
+ buffer->trans_index = index;
+ dloader_record_timestamp(0x50000000|(index<<24)|buffer->buffer[index].write_point);
+ if(buffer->save_index == index)
+ buffer->save_index = 1- index;
+ return index;
+ }
+ index = 1 - index;
+ }
+ local_irq_restore(flags);
+ spin_unlock_irqrestore(&buffer_lock, flags);
+ }
+ return 0xFF;
+}
+
+void pingpang_buffer_send_complete(struct modem_buffer *buffer,int index)
+{
+ if(buffer->type == BUF_SEND){
+ if(buffer->trans_index == index){
+ buffer->trans_count += buffer->buffer[index].write_point;
+ buffer->buffer[index].write_point = 0;
+ buffer->buffer[index].read_point = 0;
+ buffer->trans_index = 0xFF;
+ buffer->buffer[index].status = BUF_STATUS_IDLE;
+ up(&buffer->buf_write_sem);
+ }
+ }
+}
+
+int pingpang_buffer_write(struct modem_buffer *buffer,char *data,int size)
+{
+ int index = 0;
+ int data_size;
+ int free_space;
+ int write_point;
+ int save_flag = 0;
+ int i;
+ unsigned long flags;
+ enum BUF_status_t status;
+
+ if(buffer->type == BUF_SEND){
+ if (size >= buffer->buffer[0].size)
+ return 0;
+
+ do{
+ index = buffer->save_index;
+ for(i=0;i<2;i++){
+ local_irq_save(flags);
+ status = buffer->buffer[index].status;
+ if ((status != BUF_STATUS_SENT) &&
+ (status != BUF_STATUS_FULL) &&
+ (status != BUF_STATUS_WRITTEN)) {
+ buffer->buffer[index].status = BUF_STATUS_WRITTEN;
+ local_irq_restore(flags);
+ data_size = buffer_data_size(&buffer->buffer[index]);
+ free_space = buffer->buffer[index].size -1 - data_size;
+ if(free_space < size){
+ buffer->buffer[index].status = BUF_STATUS_FULL;
+ if(buffer->trans_index == 0xFF)
+ buffer->trans_index = index;
+ index = 1 - index;
+ buffer->save_index = index;
+ } else {
+ write_point = buffer->buffer[index].write_point;
+ for(i=0;i<size;i++){
+ buffer->buffer[index].addr[write_point++]=data[i];
+ if(write_point >= buffer->buffer[index].size)
+ write_point = 0;
+ }
+ dloader_record_timestamp(0x10000000|(index<<24)|buffer->buffer[index].write_point);
+ dloader_record_timestamp(0x20000000|(index<<24)|write_point);
+ buffer->buffer[index].write_point = write_point;
+ buffer->buffer[index].status = BUF_STATUS_NOEMPTY;
+ buffer->buffer[index].status = BUF_STATUS_FULL;
+ if(buffer->trans_index == 0xFF)
+ buffer->trans_index = index;
+ save_flag = 1;
+ }
+ } else {
+ local_irq_restore(flags);
+ index = 1 - index;
+ }
+ }
+ if(save_flag==0)
+ down(&buffer->buf_write_sem);
+ }while(save_flag == 0);
+ }
+ return size;
+}
+int pingpang_buffer_init(struct modem_buffer *buffer)
+{
+ char *address;
+ int divide = 2;
+
+ address = kzalloc(RECV_BUFFER_SIZE + 128, GFP_KERNEL);
+ if (address == NULL)
+ return -ENOMEM;
+
+ if (buffer->type == BUF_RECV)
+ divide = 4;
+
+ buffer->buffer[0].addr = address+32;
+ buffer->buffer[0].size = RECV_BUFFER_SIZE - RECV_BUFFER_SIZE/divide;
+ buffer->buffer[0].write_point = 0;
+ buffer->buffer[0].read_point = 0;
+ buffer->buffer[0].status = BUF_STATUS_IDLE;
+ buffer->buffer[1].addr = address + buffer->buffer[0].size+64;
+ buffer->buffer[1].size = RECV_BUFFER_SIZE - buffer->buffer[0].size;
+ buffer->buffer[1].read_point = 0;
+ buffer->buffer[1].write_point = 0;
+ buffer->buffer[1].status = BUF_STATUS_IDLE;
+ buffer->lost_count = 0;
+ buffer->trans_count = 0;
+ buffer->save_index = 0;
+ buffer->trans_index = 0xff;
+ sema_init(&buffer->buf_read_sem,0);
+ sema_init(&buffer->buf_write_sem,0);
+ spin_lock_init(&buffer_lock);
+ return 0;
+}
+void pingpang_buffer_free(struct modem_buffer *buffer)
+{
+ if (buffer->buffer[0].addr){
+ kfree(buffer->buffer[0].addr);
+ buffer->buffer[0].addr = NULL;
+ buffer->buffer[0].size = 0;
+ buffer->buffer[0].write_point = 0;
+ buffer->buffer[0].read_point = 0;
+ buffer->buffer[0].status = 0;
+ buffer->buffer[1].addr = NULL;
+ buffer->buffer[1].size = 0;
+ buffer->buffer[1].read_point = 0;
+ buffer->buffer[1].write_point = 0;
+ buffer->buffer[1].status = 0;
+ }
+}
diff --git a/drivers/char/modem_interface/modem_buffer.h b/drivers/char/modem_interface/modem_buffer.h
new file mode 100644
index 00000000..ac31efef
--- /dev/null
+++ b/drivers/char/modem_interface/modem_buffer.h
@@ -0,0 +1,58 @@
+/*
+ * kernel/driver/char/modem_interface/modem_buffer.h
+ *
+ * Generic modem interface buffer defination.
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+#ifndef _MODEM_BUFFER_H
+#define _MODEM_BUFFER_H
+
+#define RECV_BUFFER_SIZE (65*1024)
+enum BUF_type_t{
+ BUF_SEND,
+ BUF_RECV,
+};
+
+enum BUF_status_t{
+ BUF_STATUS_IDLE,
+ BUF_STATUS_NOEMPTY,
+ BUF_STATUS_WRITTEN,
+ BUF_STATUS_FULL,
+ BUF_STATUS_SENT,
+};
+
+struct single_buffer_t{
+ char *addr;
+ int size;
+ int write_point;
+ int read_point;
+ enum BUF_status_t status;
+};
+
+struct modem_buffer{
+ struct mutex mutex;
+ struct semaphore buf_read_sem;
+ struct semaphore buf_write_sem;
+ enum BUF_type_t type;
+ int save_index;
+ int trans_index;
+ int trans_count;
+ int lost_count;
+ struct single_buffer_t buffer[2];
+};
+
+extern int pingpang_buffer_send(struct modem_buffer *buffer);
+extern int pingpang_buffer_init(struct modem_buffer *buffer);
+extern void pingpang_buffer_free(struct modem_buffer *buffer);
+extern void pingpang_buffer_send_complete(struct modem_buffer *buffer,int index);
+extern int pingpang_buffer_read(struct modem_buffer *buffer,char *data,int size);
+extern int pingpang_buffer_write(struct modem_buffer *buffer,char *data,int size);
+extern int save_to_receive_buffer(struct modem_buffer *buffer,char *data,int size);
+#endif
diff --git a/drivers/char/modem_interface/modem_gpio_drv.c b/drivers/char/modem_interface/modem_gpio_drv.c
new file mode 100644
index 00000000..7851fb00
--- /dev/null
+++ b/drivers/char/modem_interface/modem_gpio_drv.c
@@ -0,0 +1,358 @@
+/*
+ * kernel/driver/char/modem_interface/modem_gpio_drv.c
+ *
+ * Generic modem interface gpio handling.
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/proc_fs.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <mach/modem_interface.h>
+#include <mach/globalregs.h>
+#include "modem_buffer.h"
+#include "modem_interface_driver.h"
+
+#define GPIO_INVALID 0xFFFFFFFF
+
+extern void free_irq(unsigned int irq, void *dev_id);
+extern void modem_intf_send_GPIO_message(int gpio_no,int status,int index);
+extern void modem_intf_send_ctrl_gpio_message(enum MSG_CTRL_GPIO_TYPE gpio_type, int gpio_value);
+extern void on_modem_poweron(void);
+static unsigned int cp_to_ap_rdy_irq;
+static unsigned int cp_alive_gpio_irq;
+static unsigned int cp_crash_gpio_irq;
+static unsigned int cp_watchdog_gpio_irq;
+static unsigned int modem_power_gpio;
+static unsigned int modem_reset_gpio;
+static int cp_to_ap_rdy ;
+static int cp_alive_gpio;
+static int cp_crash_gpio;
+static int cp_watchdog_gpio;
+
+
+int get_alive_status(void)
+{
+ int status = gpio_get_value(cp_alive_gpio);
+ if(status != 0)
+ return 1;
+ return 0;
+}
+int get_assert_status(void)
+{
+ int status = gpio_get_value(cp_crash_gpio);
+ if(status != 0)
+ return 1;
+ return 0;
+}
+static irqreturn_t cp_to_ap_rdy_handle(int irq, void *handle)
+{
+ int status ;
+
+ status = gpio_get_value(cp_to_ap_rdy);
+ pr_debug("modem_boot_irq: %d \n",status);
+ if(status == 0)
+ modem_intf_send_GPIO_message(cp_to_ap_rdy,status,0);
+ else
+ modem_intf_send_GPIO_message(cp_to_ap_rdy,1,0);
+ return IRQ_HANDLED;
+}
+
+int modem_intf_get_watchdog_gpio_value()
+{
+
+ return gpio_get_value(cp_watchdog_gpio);
+}
+static irqreturn_t cp_watchdog_gpio_handle(int irq, void * handle)
+{
+ int wdg_reset_status;
+
+ wdg_reset_status = gpio_get_value(cp_watchdog_gpio);
+ printk("cp_watchdog_gpio: %d \n",wdg_reset_status);
+
+ if(wdg_reset_status == 0) {
+ irq_set_irq_type(cp_watchdog_gpio_irq, IRQ_TYPE_LEVEL_HIGH);
+ } else {
+ irq_set_irq_type(cp_watchdog_gpio_irq, IRQ_TYPE_LEVEL_LOW);
+ }
+
+ modem_intf_send_ctrl_gpio_message(GPIO_WATCHDOG, wdg_reset_status);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cp_alive_gpio_handle(int irq, void *handle)
+{
+ int alive_status;
+
+ alive_status = gpio_get_value(cp_alive_gpio);
+ printk("cp_alive_gpio: %d \n",alive_status);
+
+ if(alive_status == 0) {
+ irq_set_irq_type(cp_alive_gpio_irq, IRQ_TYPE_LEVEL_HIGH);
+ } else {
+ irq_set_irq_type(cp_alive_gpio_irq, IRQ_TYPE_LEVEL_LOW);
+ }
+
+ modem_intf_send_ctrl_gpio_message(GPIO_ALIVE, alive_status);
+ return IRQ_HANDLED;
+}
+
+
+static irqreturn_t cp_crash_gpio_handle(int irq, void *handle)
+{
+ int assert_status;
+
+ assert_status = gpio_get_value(cp_crash_gpio);
+ printk("cp_crash_gpio: %d \n",assert_status);
+
+ if(assert_status == 0) {
+ irq_set_irq_type(cp_crash_gpio_irq, IRQ_TYPE_LEVEL_HIGH);
+ } else {
+ irq_set_irq_type(cp_crash_gpio_irq, IRQ_TYPE_LEVEL_LOW);
+ }
+
+ modem_intf_send_ctrl_gpio_message(GPIO_RESET, assert_status);
+ return IRQ_HANDLED;
+}
+
+int modem_share_gpio_init(void *para)
+{
+ struct modem_intf_platform_data *modem_config = (struct modem_intf_platform_data *)para;
+ int error = 0;
+ int status = 0;
+
+ pr_debug("modem_share_gpio_init start!!! \n");
+ cp_to_ap_rdy = modem_config->modem_boot_gpio;
+
+ error = gpio_request(cp_to_ap_rdy, "modem_boot_gpio");
+ if (error) {
+ pr_err("Cannot request GPIO %d\n", cp_to_ap_rdy);
+ gpio_free(cp_to_ap_rdy);
+ return error;
+ }
+
+ gpio_direction_input(cp_to_ap_rdy);
+ gpio_export(cp_to_ap_rdy,0);
+ cp_to_ap_rdy_irq = gpio_to_irq(cp_to_ap_rdy);
+ if (cp_to_ap_rdy_irq < 0)
+ return -1;
+ error = request_threaded_irq(cp_to_ap_rdy_irq, cp_to_ap_rdy_handle,
+ NULL, IRQF_DISABLED|IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING, "modem_boot", para);
+ if (error) {
+ printk("lee :cannot alloc cp_to_ap_rdy_irq, err %d\r\n", error);
+ gpio_free(cp_to_ap_rdy);
+ return error;
+ }
+
+ status = gpio_get_value(cp_to_ap_rdy);
+ if(status == 0)
+ modem_intf_send_GPIO_message(cp_to_ap_rdy,status,0);
+ else
+ modem_intf_send_GPIO_message(cp_to_ap_rdy,1,0);
+
+ return 0;
+}
+
+int modem_share_gpio_uninit(void *para)
+{
+ struct modem_intf_platform_data *modem_config = (struct nodem_intf_platform_data *)para;
+
+ pr_debug("modem_gpio_init start!!! \n");
+ cp_to_ap_rdy = modem_config->modem_boot_gpio;
+
+ cp_to_ap_rdy_irq = gpio_to_irq(cp_to_ap_rdy);
+ if (cp_to_ap_rdy_irq < 0)
+ return -1;
+ free_irq( cp_to_ap_rdy_irq, para);
+ gpio_free(cp_to_ap_rdy);
+
+ return 0;
+}
+
+int modem_gpio_irq_init(void *para)
+{
+ int error = 0;
+
+ cp_watchdog_gpio_irq = gpio_to_irq(cp_watchdog_gpio);
+ if(cp_watchdog_gpio_irq < 0)
+ return -1;
+ error = request_threaded_irq(cp_watchdog_gpio_irq, cp_watchdog_gpio_handle,
+ NULL, IRQF_DISABLED|IRQF_NO_SUSPEND |IRQF_TRIGGER_LOW, "modem_watchdog", para);
+ if (error) {
+ printk("modem_intf :cannot alloc cp_watchdog irq, err %d\r\n", error);
+ gpio_free(cp_watchdog_gpio);
+ return error;
+ }
+
+ enable_irq_wake(cp_watchdog_gpio_irq);
+
+ cp_alive_gpio_irq = gpio_to_irq(cp_alive_gpio);
+ if (cp_alive_gpio_irq < 0)
+ return -1;
+ error = request_threaded_irq(cp_alive_gpio_irq, cp_alive_gpio_handle,
+ NULL, IRQF_DISABLED|IRQF_NO_SUSPEND |IRQF_TRIGGER_HIGH, "modem_alive", para);
+ if (error) {
+ printk("modem_intf :cannot alloc cp_alive irq, err %d\r\n", error);
+ gpio_free(cp_alive_gpio);
+ return error;
+ }
+
+ enable_irq_wake(cp_alive_gpio_irq);
+
+ cp_crash_gpio_irq = gpio_to_irq(cp_crash_gpio);
+ if (cp_crash_gpio_irq < 0)
+ return -1;
+ error = request_threaded_irq(cp_crash_gpio_irq, cp_crash_gpio_handle,
+ NULL, IRQF_DISABLED|IRQF_NO_SUSPEND |IRQF_TRIGGER_HIGH, "modem_crash", para);
+ if (error) {
+ printk("modem_intf :cannot alloc cp_crash irq, err %d\r\n", error);
+ gpio_free(cp_crash_gpio);
+ return error;
+ }
+
+ enable_irq_wake(cp_crash_gpio_irq);
+}
+
+
+int modem_gpio_init(void *para)
+{
+ struct modem_intf_platform_data *modem_config = (struct modem_intf_platform_data *)para;
+ int error = 0;
+
+ pr_debug("modem_gpio_init start!!! \n");
+ cp_to_ap_rdy = modem_config->modem_boot_gpio;
+ cp_watchdog_gpio = modem_config->modem_watchdog_gpio;
+ cp_alive_gpio = modem_config->modem_alive_gpio;
+ cp_crash_gpio = modem_config->modem_crash_gpio;
+ modem_power_gpio = modem_config->modem_power_gpio;
+ modem_reset_gpio = modem_config->modem_reset_gpio;
+
+ if(GPIO_INVALID != modem_power_gpio) {
+ gpio_request(modem_power_gpio, "modem_power_gpio");
+ gpio_export(modem_power_gpio,0);
+ }
+
+ if(GPIO_INVALID != modem_reset_gpio) {
+ gpio_request(modem_reset_gpio, "modem_reset_gpio");
+ gpio_export(modem_reset_gpio,0);
+ }
+
+ //watchdog gpio
+ error = gpio_request(cp_watchdog_gpio, "modem_watchdog_gpio");
+ if (error) {
+ pr_err("Cannot request GPIO %d\n", cp_watchdog_gpio);
+ gpio_free(cp_watchdog_gpio);
+ return error;
+ }
+ gpio_export(cp_watchdog_gpio,0);
+ gpio_direction_input(cp_watchdog_gpio);
+
+
+//////////////////////////////////////////////////
+ //alive gpio
+ error = gpio_request(cp_alive_gpio, "modem_alive_gpio");
+ if (error) {
+ pr_err("Cannot request GPIO %d\n", cp_alive_gpio);
+ gpio_free(cp_alive_gpio);
+ return error;
+ }
+ gpio_export(cp_alive_gpio,0);
+ gpio_direction_input(cp_alive_gpio);
+
+ //crash gpio
+ error = gpio_request(cp_crash_gpio, "modem_crash_gpio");
+ if (error) {
+ pr_err("Cannot request GPIO %d\n", cp_crash_gpio);
+ gpio_free(cp_crash_gpio);
+ return error;
+ }
+ gpio_export(cp_crash_gpio,0);
+ gpio_direction_input(cp_crash_gpio);
+
+/////////////////////////////////////////////////
+
+ return 0;
+}
+
+int modem_gpio_uninit(void *para)
+{
+ modem_share_gpio_uninit(para);
+ return 0;
+}
+
+void modem_poweron_async_step1(void)
+{
+ if(GPIO_INVALID != modem_power_gpio) {
+ printk(KERN_ERR "modem_poweron_async_step1!!! \n");
+ gpio_direction_output(modem_power_gpio, 1);
+ } else {
+ printk(KERN_ERR "modem_poweron_async_step1 modem_power_gpio == GPIO_INVALID!!! \n");
+ }
+}
+
+void modem_poweron_async_step2(void)
+{
+ if(GPIO_INVALID != modem_power_gpio) {
+ gpio_set_value(modem_power_gpio, 0);
+ printk(KERN_ERR "modem_poweron_async_step2!!! \n");
+ } else {
+ printk(KERN_ERR "modem_poweron_async_step2 modem_power_gpio == GPIO_INVALID!!! \n");
+ }
+}
+
+void modem_poweron(void)
+{
+ printk("modem power on!!! \n");
+ if(GPIO_INVALID != modem_power_gpio) {
+ gpio_direction_output(modem_power_gpio, 1); //2012.1.10
+ //gpio_set_value(modem_power_gpio, 1);
+ msleep(2000);
+ gpio_set_value(modem_power_gpio, 0);
+ } else {
+ //sprd_greg_clear_bits(REG_TYPE_GLOBAL, 0x00000040, 0x4C);
+ }
+}
+void modem_poweroff(void)
+{
+ printk("modem power off!!! \n");
+ if (GPIO_INVALID != modem_power_gpio) {
+ gpio_direction_output(modem_power_gpio, 1); //2012.1.10
+ //gpio_set_value(modem_power_gpio, 1);
+ msleep(3500);//should be matched with Adie config of cp
+ gpio_set_value(modem_power_gpio, 0);
+ } else {
+ //sprd_greg_set_bits(REG_TYPE_GLOBAL, 0x00000040, 0x4C);
+ }
+}
+
+void modem_soft_reset(void)
+{
+ printk(KERN_INFO "modem soft reset enter \n");
+ if (GPIO_INVALID != modem_reset_gpio) {
+ gpio_direction_output(modem_reset_gpio, 1); //2012.1.10
+ //gpio_set_value(modem_power_gpio, 1);
+ msleep(50);
+ gpio_set_value(modem_reset_gpio, 0);
+ }
+}
+
+void modem_hard_reset(void)
+{
+ printk(KERN_INFO "modem hard reset enter \n");
+ if (GPIO_INVALID != modem_power_gpio) {
+ gpio_direction_output(modem_power_gpio, 1); //2012.1.10
+ //gpio_set_value(modem_power_gpio, 1);
+ msleep(7100);
+ gpio_set_value(modem_power_gpio, 0);
+ }
+}
diff --git a/drivers/char/modem_interface/modem_interface_driver.c b/drivers/char/modem_interface/modem_interface_driver.c
new file mode 100644
index 00000000..862c32ea
--- /dev/null
+++ b/drivers/char/modem_interface/modem_interface_driver.c
@@ -0,0 +1,1088 @@
+/* driver/char/modem_interface/modem_interface_drv.c
+ *
+ * modem interface API for dloader driver and API for application layer
+ *
+ * Copyright (C) 2012 Spreadtrum
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <mach/modem_interface.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/sched.h>
+#include<linux/spinlock.h>
+#include "modem_buffer.h"
+#include "modem_interface_driver.h"
+#include <mach/globalregs.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+
+#define MAX_MSG_NODE_NUM 32
+#define BUSY_BIT 0x8000
+#define MAX_WAIT_WATCHDOG_TIME 5
+
+extern int get_alive_status(void);
+extern int get_assert_status(void);
+extern int modem_gpio_uninit(void *para);
+extern int modem_gpio_init(void *para);
+extern int modem_share_gpio_uninit(void *para);
+extern int modem_share_gpio_init(void *para);
+extern void mux_ipc_enable(u8 is_enable);
+extern void modem_gpio_irq_init(void* para);
+extern void modem_poweron_async_step1(void);
+extern void modem_poweron_async_step2(void);
+
+extern struct modem_device_operation *modem_sdio_drv_init(void);
+extern int modem_gpio_init(void *para);
+extern void modem_poweron(void);
+extern void modem_poweroff(void);
+extern void Set_modem_status(unsigned char modem_status);
+extern void modem_soft_reset(void);
+extern void modem_hard_reset(void);
+extern void sdio_ipc_enable(u8 is_enable);
+extern void shutdown_protocol(struct modem_message_node *msg);
+extern void bootcomp_protocol(struct modem_message_node *msg);
+extern void reset_protocol(struct modem_message_node *msg);
+extern int modem_intf_get_watchdog_gpio_value();
+
+
+
+int modem_intf_send_boot_message(void);
+void modem_intf_reboot_routine(void);
+void modem_intf_alive_routine(void);
+void modem_intf_assert_routine(void);
+void modem_intf_wdg_reset_routine(void);
+
+
+static struct modem_intf_device *modem_intf_device = NULL;
+
+static struct modem_message_node *msg_nodes=NULL;
+static atomic_t nodes_count;
+static int lost_msg_count;
+static LIST_HEAD(msg_list);
+static struct semaphore msg_list_sem;
+static struct semaphore modem_event_sem;
+static int modem_gpio_status[CTRL_GPIO_MAX];
+static int modem_event = MODEM_INTF_EVENT_SHUTDOWN;
+static struct wake_lock s_modem_intf_proc_wake_lock;
+static struct wake_lock s_modem_intf_msg_wake_lock;
+static struct wake_lock s_modem_intf_event_wake_lock;
+static struct timer_list s_modem_watch_timer;
+
+
+
+//wait_queue_head_t mdoem_mode_normal;
+spinlock_t int_lock;
+struct modem_device_operation *devices_op[8] = {NULL};
+
+/************ modemsts notifier *****************/
+static LIST_HEAD(modemsts_chg_handlers);
+static DEFINE_MUTEX(modemsts_chg_lock);
+
+/* register a callback function when modem status changed
+* @handler: callback function
+*/
+int modemsts_notifier_register(struct modemsts_chg *handler)
+{
+
+ struct list_head *pos;
+ struct modemsts_chg *e;
+
+ mutex_lock(&modemsts_chg_lock);
+ list_for_each(pos, &modemsts_chg_handlers) {
+ e = list_entry(pos, struct modemsts_chg, link);
+ if(e == handler){
+ printk("***** %s, %pf already exsited ****\n",
+ __func__, e->modemsts_notifier);
+ return -1;
+ }
+ }
+ list_for_each(pos, &modemsts_chg_handlers) {
+ struct modemsts_chg *e;
+ e = list_entry(pos, struct modemsts_chg, link);
+ if (e->level > handler->level)
+ break;
+ }
+ list_add_tail(&handler->link, pos);
+ mutex_unlock(&modemsts_chg_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(modemsts_notifier_register);
+
+/* unregister a callback function for detecting modem status change
+* @handler: callback function
+*/
+int modemsts_notifier_unregister(struct modemsts_chg *handler)
+{
+ mutex_lock(&modemsts_chg_lock);
+ list_del(&handler->link);
+ mutex_unlock(&modemsts_chg_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(modemsts_notifier_unregister);
+
+void modemsts_change_notification(unsigned int state)
+{
+ struct modemsts_chg *pos;
+
+ mutex_lock(&modemsts_chg_lock);
+ if(state == MODEM_STATUS_REBOOT) {
+ list_for_each_entry(pos, &modemsts_chg_handlers, link) {
+ if (pos->modemsts_notifier != NULL) {
+ pos->modemsts_notifier(pos, state);
+ }
+ }
+ } else {
+ list_for_each_entry_reverse(pos, &modemsts_chg_handlers, link) {
+ if (pos->modemsts_notifier != NULL) {
+ pos->modemsts_notifier(pos, state);
+ }
+ }
+ }
+ mutex_unlock(&modemsts_chg_lock);
+}
+/************ modem notifier *****************/
+
+
+char *modem_intf_msg_string(enum MODEM_MSG_type msg)
+{
+ switch(msg) {
+ case MODEM_TRANSFER_REQ:
+ return "MODEM_TRANSFER_REQ";
+ case MODEM_TRANSFER_END:
+ return "MODEM_TRANSFER_END";
+ case MODEM_SLAVE_RTS:
+ return "MODEM_SLAVE_RTS";
+ case MODEM_SLAVE_RDY:
+ return "MODEM_SLAVE_RDY";
+ case MODEM_SET_MODE:
+ return "MODEM_SET_MODE";
+ case MODEM_CTRL_GPIO_CHG:
+ return "MODEM_CTRL_GPIO_CHG";
+ case MODEM_USER_REQ:
+ return "MODEM_USER_REQ";
+ case MODEM_BOOT_CMP:
+ return "MODEM_BOOT_CMP";
+ case MODEM_OPEN_DEVICE:
+ return "MODEM_OPEN_DEVICE";
+ default:
+ break;
+ }
+ return "UNKNOWN MSG";
+}
+static void modem_intf_register_device_operation(struct modem_device_operation *op)
+{
+ int i;
+ for(i=0; i<8; i++) {
+ if(devices_op[i] == NULL)
+ devices_op[i] = op;
+ }
+}
+static struct modem_device_operation *modem_intf_get_device_operation(enum MODEM_device_type dev) {
+ int i;
+ for(i=0; i<8; i++) {
+ if((devices_op[i] != NULL)&&(devices_op[i]->dev == dev))
+ return devices_op[i];
+ }
+ return NULL;
+}
+static int init_msg_nodes(void)
+{
+ int i;
+
+ if(msg_nodes)
+ return 0;
+
+ msg_nodes = kzalloc(sizeof(struct modem_message_node)*MAX_MSG_NODE_NUM, GFP_KERNEL);
+ if (msg_nodes == NULL)
+ return -ENOMEM;
+
+ atomic_set(&nodes_count,0);
+ for (i=0; i<MAX_MSG_NODE_NUM; i++) {
+ msg_nodes[i].buno = i;
+ }
+ lost_msg_count = 0;
+ atomic_set(&nodes_count,i);
+ return 0;
+}
+
+static struct modem_message_node * find_msg_node(void) {
+ unsigned long flags;
+ int i;
+
+ if(atomic_read(&nodes_count) == 0)
+ return NULL;
+ //local_irq_save(flags);
+ spin_lock_irqsave(&int_lock, flags);
+ for (i=0; i<MAX_MSG_NODE_NUM; i++) {
+ if ((msg_nodes[i].buno & BUSY_BIT )==0) {
+ atomic_dec(&nodes_count);
+ msg_nodes[i].buno |= BUSY_BIT;
+ break;
+ }
+ }
+ //local_irq_restore(flags);
+ spin_unlock_irqrestore(&int_lock, flags);
+ if(i==MAX_MSG_NODE_NUM)
+ return NULL;
+ return &msg_nodes[i];
+}
+
+static void free_msg_node(struct modem_message_node *msg)
+{
+ if (msg) {
+ msg->buno &= ~BUSY_BIT;
+ atomic_inc(&nodes_count);
+ }
+}
+
+static struct modem_message_node * modem_intf_get_message( void ) {
+ struct list_head *entry;
+ struct modem_message_node *msg;
+ unsigned long flags;
+ do {
+ if(!list_empty(&msg_list))
+ break;
+ down(&msg_list_sem);
+ } while(1);
+
+ if(!list_empty(&msg_list)) {
+ entry = msg_list.next;
+ //local_irq_save(flags);
+ spin_lock_irqsave(&int_lock, flags);
+ list_del_init(entry);
+ //local_irq_restore(flags);
+ spin_unlock_irqrestore(&int_lock, flags);
+ msg = (struct modem_message_node *)list_entry(entry,struct modem_message_node,link);
+ return (struct modem_message_node *)msg;
+ }
+ return NULL;
+}
+
+static void modem_send_message( struct modem_message_node *msg )
+{
+ unsigned long flags;
+
+ wake_lock_timeout(&s_modem_intf_msg_wake_lock, HZ / 2);
+ //local_irq_save(flags);
+ spin_lock_irqsave(&int_lock, flags);
+ list_add_tail(&msg->link,&msg_list);
+ //local_irq_restore(flags);
+ spin_unlock_irqrestore(&int_lock, flags);
+ up(&msg_list_sem);
+}
+
+static int modem_protocol_thread(void *data)
+{
+ struct modem_message_node *msg;
+
+ int boot_cpu = smp_processor_id();
+ long rc;
+ struct sched_param param = {.sched_priority = 98};
+
+ current_thread_info()->cpu = boot_cpu;
+ rc = sched_setaffinity(current->pid, cpumask_of(boot_cpu));
+
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ while(1) {
+ msg = modem_intf_get_message();
+ if(msg == NULL)
+ continue;
+ wake_lock(&s_modem_intf_proc_wake_lock);
+ switch(modem_intf_device->mode) {
+ case MODEM_MODE_SHUTDOWN:
+ shutdown_protocol(msg);
+ break;
+ case MODEM_MODE_BOOT:
+ boot_protocol(msg);
+ break;
+ case MODEM_MODE_BOOTCOMP:
+ bootcomp_protocol(msg);
+ break;
+ case MODEM_MODE_NORMAL:
+ normal_protocol(msg);
+ break;
+ case MODEM_MODE_DUMP:
+ dump_memory_protocol(msg);
+ break;
+ case MODEM_MODE_RESET:
+ reset_protocol(msg);
+ break;
+ default:
+ break;
+ }
+ free_msg_node(msg);
+ wake_unlock(&s_modem_intf_proc_wake_lock);
+ }
+ return 0;
+}
+
+int modem_intf_open(enum MODEM_Mode_type mode,int index)
+{
+ int retval=0;
+
+ if(modem_intf_device == NULL)
+ return -1;
+ printk("boot gpio = %d\n",modem_intf_device->modem_config.modem_boot_gpio);
+ if(modem_intf_device->op == NULL) {
+ modem_intf_device->op = modem_intf_get_device_operation(modem_intf_device->modem_config.dev_type);
+ printk("modem_intf_open: op = %x\n",modem_intf_device->op);
+ if(modem_intf_device->op == NULL)
+ return -1;
+ }
+
+ if((modem_intf_device->op)&&(mode == MODEM_MODE_BOOT)) {
+ if(0 != modem_intf_device->op->open(NULL)) {
+ return -1;
+ }
+ }
+
+ return retval;
+}
+
+int modem_intf_send_bootcomp_message(enum MODEM_Mode_type mode,int index)
+{
+ struct modem_message_node *msg;
+
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ printk("modem_intf_send_bootcomp_message MSG LOST!!!!!!\n");
+ return -1;
+ }
+ msg->src = SRC_DLOADER;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = 0;
+ msg->type = MODEM_BOOT_CMP;
+
+ modem_send_message(msg);
+
+ return 0;
+}
+
+int modem_intf_read(char *buffer, int size,int index)
+{
+ int read_len;
+
+ if(modem_intf_device->mode == MODEM_MODE_UNKNOWN)
+ return 0;
+
+ read_len = pingpang_buffer_read(&modem_intf_device->recv_buffer,buffer,size);
+ return read_len;
+}
+
+int modem_intf_write(char *buffer, int size,int index)
+{
+ struct modem_message_node *msg;
+ if(modem_intf_device->mode == MODEM_MODE_UNKNOWN)
+ return 0;
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ return -1;
+ }
+ if(buffer && size )
+ pingpang_buffer_write(&modem_intf_device->send_buffer,buffer,size);
+ msg->type = MODEM_TRANSFER_REQ;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = 0;
+ modem_send_message(msg);
+ return size;
+}
+
+void modem_intf_set_mode(enum MODEM_Mode_type mode,int force)
+{
+
+ printk(KERN_INFO "modem_intf_set_mode enter old:%d,new:%d\n",
+ modem_intf_device->mode, mode);
+
+ if(modem_intf_device->mode == mode) {
+ goto fin;
+ }
+
+ if(force) {
+ modem_intf_device->mode = mode;
+ goto fin;
+ }
+
+ switch(modem_intf_device->mode) {
+ case MODEM_MODE_BOOT:
+ if(MODEM_MODE_NORMAL == mode || MODEM_MODE_BOOTCOMP == mode) {
+ modem_intf_device->mode = mode;
+ } else {
+ printk(KERN_ERR "modem_intf: try to enter mode:%d, in MODEM_MODE_BOOT", mode);
+ }
+ break;
+ case MODEM_MODE_BOOTCOMP:
+ if(MODEM_MODE_NORMAL == mode) {
+ modem_intf_device->mode = mode;
+ } else {
+ printk(KERN_ERR "modem_intf: try to enter mode:%d, in MODEM_MODE_BOOTCOMP", mode);
+ }
+ break;
+ case MODEM_MODE_NORMAL:
+ if(MODEM_MODE_DUMP == mode || MODEM_MODE_RESET == mode) {
+ modem_intf_device->mode = mode;
+ } else {
+ printk(KERN_ERR "modem_intf: try to enter mode:%d, in MODEM_MODE_NORMAL", mode);
+ }
+ break;
+ case MODEM_MODE_DUMP:
+ if(MODEM_MODE_RESET == mode || MODEM_MODE_BOOT == mode) {
+ modem_intf_device->mode = mode;
+ } else {
+ printk(KERN_ERR "modem_intf: try to enter mode:%d, in MODEM_MODE_DUMP", mode);
+ }
+ break;
+ default: //MODEM_MODE_RESET
+ if(MODEM_MODE_BOOT == mode) {
+ modem_intf_device->mode = mode;
+ } else {
+ printk(KERN_ERR "modem_intf: try to enter mode:%d, in MODEM_MODE_RESET", mode);
+ }
+ break;
+ }
+
+fin:
+ printk(KERN_INFO "modem_intf_set_mode leave new:%d\n", modem_intf_device->mode);
+}
+
+void modem_intf_send_channel_message(int dir,int para,int index)
+{
+ struct modem_message_node *msg;
+
+ if(modem_intf_device->mode == MODEM_MODE_UNKNOWN)
+ return ;
+ if(modem_intf_device->mode != MODEM_MODE_NORMAL)
+ return;
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ return ;
+ }
+
+ msg->src = SRC_SPI;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = dir;
+ msg->type = MODEM_TRANSFER_END;
+ modem_send_message(msg);
+}
+
+void modem_intf_send_ctrl_gpio_message(enum MSG_CTRL_GPIO_TYPE gpio_type, int gpio_value)
+{
+ struct modem_message_node *msg;
+
+ printk("ctrl_gpio: gpio_type = %d value = %d\n", gpio_type, gpio_value);
+
+ if(modem_gpio_status[gpio_type] == gpio_value) {
+ return;
+ }
+
+ modem_gpio_status[gpio_type] = gpio_value;
+
+ //ctrl gpio only effective in these modem mode
+ if(modem_intf_device->mode != MODEM_MODE_BOOT &&
+ modem_intf_device->mode != MODEM_MODE_BOOTCOMP &&
+ modem_intf_device->mode != MODEM_MODE_NORMAL &&
+ modem_intf_device->mode != MODEM_MODE_DUMP) {
+
+ return;
+ }
+
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ printk("modem_intf_send_ctrl_gpio_message MSG LOST!!!!!!\n");
+ return ;
+ }
+ msg->src = SRC_GPIO;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = ((gpio_type << 16) | gpio_value);
+ msg->type = MODEM_CTRL_GPIO_CHG;
+
+ modem_send_message(msg);
+}
+
+void modem_intf_send_user_req_message(int req)
+{
+ struct modem_message_node *msg;
+
+retry:
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ printk("modem_intf_send_user_reboot_req_message MSG LOST!!!!!!\n");
+
+ msleep(100);
+ printk("modem_intf_send_user_reboot_req_message retry!!!!!!\n");
+ goto retry;
+ }
+ msg->src = SRC_USER;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = req;
+ msg->type = MODEM_USER_REQ;
+
+ modem_send_message(msg);
+}
+
+
+int modem_intf_send_boot_message()
+{
+ struct modem_message_node *msg;
+
+retry:
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ printk("modem_intf_send_boot_message MSG LOST retry!!!!!!\n");
+
+ msleep(100);
+ goto retry;
+ }
+ msg->src = SRC_DLOADER;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = MODEM_MODE_BOOT;
+ msg->type = MODEM_SET_MODE;
+
+ modem_send_message(msg);
+
+ return 0;
+}
+
+int modem_intf_send_shutdown_message()
+{
+ struct modem_message_node *msg;
+
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ printk("modem_intf_send_shutdown_message MSG LOST !!!!!!\n");
+
+ return 0;
+ }
+ msg->src = SRC_DLOADER;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = MODEM_MODE_SHUTDOWN;
+ msg->type = MODEM_SET_MODE;
+
+ modem_send_message(msg);
+
+ return 0;
+}
+
+
+
+
+void modem_intf_send_GPIO_message(int gpio_no,int status,int index)
+{
+ struct modem_message_node *msg;
+
+ printk("GPIO_MSG: mode = %d gpio=%d status = %d\n",modem_intf_device->mode,gpio_no,status);
+ if(modem_intf_device->mode == MODEM_MODE_UNKNOWN)
+ return ;
+ msg = find_msg_node();
+ if (msg == NULL) {
+ lost_msg_count++;
+ printk("modem_intf_send_GPIO_message MSG LOST!!!!!!\n");
+ return ;
+ }
+ msg->src = SRC_GPIO;
+ msg->parameter1 = (int)modem_intf_device;
+ msg->parameter2 = gpio_no|(status << 16);
+ if(modem_intf_device->mode == MODEM_MODE_NORMAL) {
+ if (gpio_no == modem_intf_device->modem_config.modem_boot_gpio) {
+ msg->type = MODEM_SLAVE_RDY;
+ } else if (gpio_no == modem_intf_device->modem_config.modem_crash_gpio) {
+ msg->type = MODEM_SLAVE_RTS;
+ } else if (gpio_no == modem_intf_device->modem_config.modem_alive_gpio) {
+ msg->type = MODEM_SLAVE_RTS;
+ }
+ } else if(modem_intf_device->mode == MODEM_MODE_BOOT) {
+ if ((gpio_no == modem_intf_device->modem_config.modem_boot_gpio)) {
+ if ( status != 0)
+ msg->type = MODEM_SLAVE_RTS;
+ else
+ msg->type = MODEM_TRANSFER_END;
+ }
+ } else if(modem_intf_device->mode == MODEM_MODE_DUMP) {
+ if (gpio_no == modem_intf_device->modem_config.modem_crash_gpio) {
+ msg->type = MODEM_SLAVE_RTS;
+ }
+ } else {
+ free_msg_node(msg);
+ return;
+ }
+ modem_send_message(msg);
+}
+static int modem_intf_driver_remove( struct platform_device *_dev)
+{
+ return 0;
+}
+
+/**
+ * This function shows the modem state
+ */
+static ssize_t modem_intf_state_show(struct device *dev,struct device_attribute *attr, char *buf)
+{
+ int ret;
+ printk("call modem_intf_state_show\n");
+ ret = down_interruptible(&modem_event_sem);
+ if(ret == -EINTR)
+ return ret;
+ printk("event available:%d ...\n",modem_event);
+ snprintf(buf,4,"%d\n",modem_event);
+ printk("event = %s\n",buf);
+ return strlen(buf);
+}
+
+extern void mux_ipc_enable(u8 is_enable);
+
+
+void modem_intf_send_event(int event)
+{
+ //user space process should wait for modem_event_sem
+ wake_lock_timeout(&s_modem_intf_event_wake_lock, HZ / 2);
+ modem_event = event;
+ up(&modem_event_sem);
+}
+
+void modem_intf_cp_reset_req_routine()
+{
+ modem_intf_send_event(MODEM_INTF_EVENT_CP_REQ_RESET);
+}
+
+
+void modem_intf_reboot_routine()
+{
+ //disable mux sdio spi
+ mux_ipc_enable(0);
+ sdio_ipc_enable(0);
+ modemsts_change_notification(MODEM_STATUS_REBOOT);
+ //modem_share_gpio_init(&(modem_intf_device->modem_config));
+
+ modem_intf_set_mode(MODEM_MODE_RESET, 0);
+
+ modem_intf_send_event(MODEM_INTF_EVENT_FORCE_RESET);
+}
+
+void modem_intf_alive_routine()
+{
+ //msleep(10*1000);
+ modem_intf_set_mode(MODEM_MODE_NORMAL, 0);
+ modem_share_gpio_uninit(&(modem_intf_device->modem_config));
+ sdio_ipc_enable(1);
+ modemsts_change_notification(MODEM_STATUS_ALVIE);
+ mux_ipc_enable(1);
+ modem_intf_send_event(MODEM_INTF_EVENT_ALIVE);
+}
+
+void modem_intf_assert_routine()
+{
+ modemsts_change_notification(MODEM_STATUS_ASSERT);
+ modem_intf_send_event(MODEM_INTF_EVENT_ASSERT);
+}
+
+void modem_intf_wdg_reset_routine(void)
+{
+ modem_intf_send_event(MODEM_INTF_EVENT_WDG_RESET);
+}
+
+int chk_watchdog_reset()
+{
+ unsigned long now = jiffies;
+
+ do {
+ udelay(10);
+ if(1 == modem_intf_get_watchdog_gpio_value())
+ {
+ return 1;
+ }
+
+ }while((msecs_to_jiffies(jiffies - now) < MAX_WAIT_WATCHDOG_TIME));
+
+ return 0;
+}
+void modem_intf_ctrl_gpio_handle_normal(int status)
+{
+ int type, value;
+
+ type = status >> 16;
+ value = status & 0xFFFF;
+
+ switch(type) {
+ case GPIO_RESET:
+ //reset -> 1, ,means need reboot
+ if(value) {
+ //modem_intf_assert_routine();
+ modem_intf_set_mode(MODEM_MODE_DUMP, 0);
+ modem_intf_cp_reset_req_routine();
+ }
+ break;
+ case GPIO_ALIVE:
+ //alive -> 0,means assert
+ if(!value) {
+ //first check if watch dog reset changes cp_alive
+ if(chk_watchdog_reset()) {
+ printk("modem_intf: found watchdog reset in GPIO_ALIVE handle\n");
+ modem_intf_wdg_reset_routine();
+ modem_intf_set_mode(MODEM_MODE_DUMP, 0);
+ break;
+ }
+ modem_intf_assert_routine();
+ modem_intf_set_mode(MODEM_MODE_DUMP, 0);
+ }
+ break;
+ case GPIO_WATCHDOG:
+ //watchdog -> 0,means watch dog reset
+ if(value) {
+ modem_intf_wdg_reset_routine();
+ modem_intf_set_mode(MODEM_MODE_DUMP, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+}
+
+void modem_intf_ctrl_gpio_handle_dump(int status)
+{
+ int type, value;
+
+ type = status >> 16;
+ value = status & 0xFFFF;
+
+ switch(type) {
+ case GPIO_RESET:
+ //reset -> 1,means need reboot
+ if(value) {
+ modem_intf_cp_reset_req_routine();
+ }
+ break;
+ case GPIO_ALIVE:
+
+ break;
+ case GPIO_WATCHDOG:
+
+ break;
+ default:
+ break;
+ }
+
+}
+
+void modem_intf_ctrl_gpio_handle_boot(int status)
+{
+ int type, value;
+
+ type = status >> 16;
+ value = status & 0xFFFF;
+
+ switch(type) {
+ case GPIO_RESET:
+ break;
+ case GPIO_ALIVE:
+ //alive -> 1, means alive
+ if(value) {
+ modem_intf_alive_routine();
+ }
+ break;
+ case GPIO_WATCHDOG:
+ break;
+ default:
+ break;
+ }
+
+}
+
+void modem_intf_ctrl_gpio_handle_bootcomp(int status)
+{
+ int type, value;
+
+ type = status >> 16;
+ value = status & 0xFFFF;
+
+ switch(type) {
+ case GPIO_RESET:
+ break;
+ case GPIO_ALIVE:
+ //alive -> 1, means alive
+ if(value) {
+ modem_intf_alive_routine();
+ }
+ break;
+ case GPIO_WATCHDOG:
+ break;
+ default:
+ break;
+ }
+
+}
+
+
+static ssize_t modem_intf_state_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
+{
+ int status;
+
+ printk("modem_intf_state_store :%d : %s\n",modem_gpio_status,buf);
+ status = simple_strtoul(buf, NULL, 16);
+ //status 0, mean enter boot mode
+ if(0 == status) {
+ //status 0 means start to boot cp
+ modem_share_gpio_init(&(modem_intf_device->modem_config));
+
+ printk("modem_intf_open: modem_intf_send_boot_message mode = %d\n", MODEM_MODE_BOOT);
+ modem_intf_send_boot_message();
+ } else {
+ modem_intf_send_user_req_message(status);
+ }
+
+ return 0;
+}
+
+DEVICE_ATTR(state, S_IRUGO | S_IWUSR, modem_intf_state_show,modem_intf_state_store);
+
+static int s_modem_poweron = 0;
+
+void on_modem_poweron()
+{
+ modem_gpio_irq_init(&(modem_intf_device->modem_config));
+ modemsts_change_notification(MODEM_STATUS_POWERON);
+}
+
+static ssize_t modem_intf_modempower_show(struct device *dev,struct device_attribute *attr, char *buf)
+{
+ int count=0;
+
+ if(buf == NULL)
+ return 0;
+ printk("modempower_show: %d\n",s_modem_poweron);
+
+ if(s_modem_poweron == 0) {
+ snprintf(buf,4,"off");
+ count = 4;
+ } else {
+ snprintf(buf,3,"on");
+ count = 3;
+ }
+ return count;
+}
+
+static ssize_t modem_intf_modempower_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
+{
+ int power;
+
+ if(buf == NULL)
+ return 0;
+ power = simple_strtoul(buf, NULL, 16);
+ if (power == 1) {
+ if(s_modem_poweron)
+ return size;
+ modem_poweron();
+ s_modem_poweron = 1;
+ on_modem_poweron();
+ } else if(power == 0) {
+ if(!s_modem_poweron)
+ return size;
+ modem_poweroff();
+ s_modem_poweron = 0;
+ }
+ return size;
+}
+
+DEVICE_ATTR(modempower, S_IRUGO | S_IWUSR, modem_intf_modempower_show,modem_intf_modempower_store);
+
+static void modem_intf_init_poweron_timeout(unsigned long priv)
+{
+ modem_poweron_async_step2();
+ s_modem_poweron = 1;
+ on_modem_poweron();
+}
+
+static void modem_intf_init_poweron_modem()
+{
+ init_timer(&s_modem_watch_timer);
+ s_modem_watch_timer.expires = jiffies + (2 * HZ);
+ s_modem_watch_timer.data = (unsigned long)NULL;
+ s_modem_watch_timer.function = modem_intf_init_poweron_timeout;
+
+ modem_poweron_async_step1();
+
+ add_timer(&s_modem_watch_timer);
+}
+
+
+static ssize_t modem_intf_modemreset_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t size)
+{
+ int power;
+
+ if(buf == NULL)
+ return 0;
+ if(!s_modem_poweron)
+ return -1;
+ power = simple_strtoul(buf, NULL, 16);
+ if (power == 1) {
+ modem_soft_reset();
+ } else if(power == 2) {
+ modem_hard_reset();
+ }
+ return size;
+}
+
+DEVICE_ATTR(modemreset, S_IWUSR, NULL,modem_intf_modemreset_store);
+
+static int modem_intf_driver_probe(struct platform_device *_dev)
+{
+ int retval = 0;
+ int i;
+ struct modem_intf_platform_data *modem_config = _dev->dev.platform_data;
+ struct modem_intf_device *device;
+
+ dev_dbg(&_dev->dev, "MODEM_INTF_driver_probe(%p)\n", _dev);
+
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+
+ if (!device) {
+ printk("MODEM device alloc memory failed!!!\n");
+ retval = -ENOMEM;
+ goto fail;
+ }
+
+ memcpy(&device->modem_config,modem_config,sizeof(*modem_config));
+ device->send_buffer.type = BUF_SEND;
+ device->recv_buffer.type = BUF_RECV;
+ if (pingpang_buffer_init(&device->send_buffer)) {
+ dev_dbg(&_dev->dev, "send_buffer init failed\n");
+ retval = -ENOMEM;
+ goto fail;
+ }
+
+ if (pingpang_buffer_init(&device->recv_buffer)) {
+ dev_dbg(&_dev->dev, "receive_buffer init failed\n");
+ pingpang_buffer_free(&device->send_buffer);
+ retval = -ENOMEM;
+ goto fail;
+ }
+ // sprd_greg_set_bits(REG_TYPE_GLOBAL, 0x00000040, GR_PIN_CTL);
+ device->mode = MODEM_MODE_SHUTDOWN;
+ modem_intf_device = device;
+ modem_intf_device->op = NULL;
+
+ for(i = 0; i < CTRL_GPIO_MAX; i++) {
+ modem_gpio_status[i] = 0xFF;
+ }
+ retval = device_create_file(&_dev->dev, &dev_attr_state);
+ retval = device_create_file(&_dev->dev, &dev_attr_modempower);
+ retval = device_create_file(&_dev->dev, &dev_attr_modemreset);
+ modem_gpio_init(&modem_intf_device->modem_config);
+ modem_intf_register_device_operation(modem_sdio_drv_init());
+ modem_event = MODEM_INTF_EVENT_SHUTDOWN;
+ sema_init(&modem_event_sem,1);
+ spin_lock_init(&int_lock);
+ modem_intf_init_poweron_modem();
+ return 0;
+fail:
+ kfree(device);
+ modem_intf_device = NULL;
+ return retval;
+}
+
+static void modem_intf_driver_shutdown(struct platform_device *_dev)
+{
+ unsigned long timeout = jiffies + 30 * HZ;
+
+ //wait downloading cp finished
+ printk(KERN_ERR "modem_intf: modem_intf_driver_shutdown enter!\n" );
+ while(time_after(timeout, jiffies)) {
+ if(modem_intf_device->mode == MODEM_MODE_BOOT)
+ {
+ printk(KERN_ERR "modem_intf: shutdown found booting cp ...!\n" );
+ msleep(1000);
+ } else {
+ break;
+ }
+ }
+
+ //send message
+ printk(KERN_ERR "modem_intf: shutdown modem_intf_send_shutdown_message!\n" );
+ modem_intf_send_shutdown_message();
+
+ //power off modem
+ printk(KERN_ERR "modem_intf: shutdown modem_poweroff!\n" );
+ modem_poweroff();
+}
+
+
+static struct platform_driver modem_intf_driver = {
+ .driver = {
+ .name = "modem_interface",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = modem_intf_driver_probe,
+ .remove = modem_intf_driver_remove,
+ .shutdown = modem_intf_driver_shutdown,
+
+};
+static int __init init(void)
+{
+ int retval = 0;
+ struct task_struct * task;
+ printk(KERN_INFO "MODEM_INF_DRIVER: version 0.1\n" );
+
+ //init_waitqueue_head(&mdoem_mode_normal);
+ sema_init(&msg_list_sem,0);
+ retval = init_msg_nodes();
+ retval = platform_driver_probe(&modem_intf_driver, modem_intf_driver_probe);
+ if (retval < 0) {
+ printk(KERN_ERR "%s retval=%d\n", __func__, retval);
+ }
+ if(retval < 0)
+ return retval;
+
+ wake_lock_init(&s_modem_intf_proc_wake_lock, WAKE_LOCK_SUSPEND, "modem_if_proc_lock");
+ wake_lock_init(&s_modem_intf_msg_wake_lock, WAKE_LOCK_SUSPEND, "modem_if_msg_lock");
+ wake_lock_init(&s_modem_intf_event_wake_lock, WAKE_LOCK_SUSPEND, "modem_if_evt_lock");
+ task = kthread_create(modem_protocol_thread, NULL, "ModemIntf");
+ if(0 != task)
+ wake_up_process(task);
+ return retval;
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+ printk(KERN_DEBUG "MODEM_INTF_driver_cleanup()\n");
+
+ if (modem_intf_device) {
+ pingpang_buffer_free(&modem_intf_device->send_buffer);
+ pingpang_buffer_free(&modem_intf_device->recv_buffer);
+ kfree(modem_intf_device);
+ modem_intf_device = NULL;
+ }
+ platform_driver_unregister(&modem_intf_driver);
+
+ printk(KERN_INFO "MODEM_INTF module removed\n" );
+}
+module_exit(cleanup);
diff --git a/drivers/char/modem_interface/modem_interface_driver.h b/drivers/char/modem_interface/modem_interface_driver.h
new file mode 100644
index 00000000..786b81ae
--- /dev/null
+++ b/drivers/char/modem_interface/modem_interface_driver.h
@@ -0,0 +1,84 @@
+#ifndef __MODEM_INTF_DRIVER_H__
+#define __MODEM_INTF_DRIVER_H__
+#include <mach/modem_interface.h>
+
+
+#define MODEM_INTF_EVENT_ASSERT 0
+#define MODEM_INTF_EVENT_ALIVE 1
+#define MODEM_INTF_EVENT_CP_REQ_RESET 2
+#define MODEM_INTF_EVENT_SHUTDOWN 4
+#define MODEM_INTF_EVENT_FORCE_RESET 8
+#define MODEM_INTF_EVENT_WDG_RESET 16
+
+
+
+
+
+enum TRAN_DIR_t{
+ TRAN_DIR_IN,
+ TRAN_DIR_OUT,
+ TRAN_DIR_NONE,
+};
+
+enum MSG_SRC_type {
+ SRC_GPIO,
+ SRC_SPI,
+ SRC_MUX,
+ SRC_DLOADER,
+ SRC_USER
+};
+
+enum MODEM_MSG_type {
+ MODEM_TRANSFER_REQ, // high layer(mux /download driver) request to send.
+ MODEM_TRANSFER_END,// transfer complete
+ MODEM_SLAVE_RTS, // MODEM request to send data
+ MODEM_SLAVE_RDY, // indicate MODEM is ready to receive.
+ MODEM_SET_MODE,
+ MODEM_CTRL_GPIO_CHG,
+ MODEM_USER_REQ,
+ MODEM_BOOT_CMP,
+ MODEM_OPEN_DEVICE
+};
+
+enum MSG_CTRL_GPIO_TYPE {
+ GPIO_ALIVE = 0,
+ GPIO_RESET,
+ GPIO_WATCHDOG,
+ CTRL_GPIO_MAX
+};
+
+
+struct modem_message_node{
+ struct list_head link;
+ int buno;
+ enum MSG_SRC_type src;
+ enum MODEM_MSG_type type;
+ int parameter1;
+ int parameter2;
+};
+
+struct modem_device_operation {
+ enum MODEM_device_type dev;
+ int (*open) (void*para);
+ int (*write)(char *buffer, int size);
+ int (*read)(char *buffer, int size);
+};
+
+typedef struct modem_intf_device {
+ struct modem_intf_platform_data modem_config;
+ enum MODEM_Mode_type mode;
+ struct modem_device_operation *op;
+ struct modem_buffer send_buffer;
+ struct modem_buffer recv_buffer;
+ enum TRAN_DIR_t direction;
+ int buffer_index;
+ int status;
+ int out_transfering;
+ int out_transfer_pending;
+} MODEM_DEV_T;
+
+extern void boot_protocol(struct modem_message_node *msg);
+extern void normal_protocol(struct modem_message_node *msg);
+extern void dump_memory_protocol(struct modem_message_node *msg);
+extern char *modem_intf_msg_string(enum MODEM_MSG_type msg);
+#endif
diff --git a/drivers/char/modem_interface/modem_sdio_drv.c b/drivers/char/modem_interface/modem_sdio_drv.c
new file mode 100644
index 00000000..efe7288b
--- /dev/null
+++ b/drivers/char/modem_interface/modem_sdio_drv.c
@@ -0,0 +1,50 @@
+/*
+ * kernel/driver/char/modem_interface/modem_sdio_drv.c
+ *
+ * Generic modem interface sdio API
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+
+
+#include <linux/mutex.h>
+#include <linux/dma-mapping.h>
+#include <linux/proc_fs.h>
+#include "modem_buffer.h"
+#include "modem_interface_driver.h"
+extern struct spi_device *sprd_spi_modem_device_register(int master_bus_num,struct spi_board_info *chip);
+
+extern int sprd_sdio_channel_open(void);
+extern void sprd_sdio_channel_close(void);
+extern int sprd_sdio_channel_rx(char *buf, int len, unsigned int addr);
+extern int sprd_sdio_channel_tx(const char *buf, unsigned int len, unsigned int addr);
+
+static int modem_sdio_open(void *para)
+{
+ return sprd_sdio_channel_open();
+}
+int modem_sdio_read(char *buffer,int size)
+{
+ return sprd_sdio_channel_rx(buffer,size, 0);
+}
+int modem_sdio_write(char *buffer,int size)
+{
+ return sprd_sdio_channel_tx((const char *)buffer,size, 0);
+}
+
+static struct modem_device_operation sdio_device_op = {
+ .dev = MODEM_DEV_SDIO,
+ .open = modem_sdio_open,
+ .read = modem_sdio_read,
+ .write =modem_sdio_write
+};
+struct modem_device_operation * modem_sdio_drv_init(void)
+{
+ return &sdio_device_op;
+}
diff --git a/drivers/char/modem_interface/modem_spi_drv.c b/drivers/char/modem_interface/modem_spi_drv.c
new file mode 100644
index 00000000..83573ed8
--- /dev/null
+++ b/drivers/char/modem_interface/modem_spi_drv.c
@@ -0,0 +1,124 @@
+/*
+ * kernel/driver/char/modem_interface/modem_spi_drv.c
+ *
+ * Generic modem interface spi API.
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/spi/spi.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include "modem_buffer.h"
+#include "modem_interface_driver.h"
+
+extern struct spi_device *sprd_spi_modem_device_register(int master_bus_num,struct spi_board_info *chip);
+
+dma_addr_t spi2_rx_buf_dma_phys;
+dma_addr_t spi2_tx_buf_dma_phys;
+void *spi2_rx_buf_dma_virt;
+void *spi2_tx_buf_dma_virt;
+
+spinlock_t write_spinlock;
+#define SPI_WRITE_DEBUG
+#ifdef SPI_WRITE_DEBUG
+spinlock_t log_spinlock;
+#endif
+
+static struct spi_device *spi_g=NULL;
+
+static int modem_spi_open(void *para)
+{
+ return 0;
+}
+int modem_spi_read(char *buffer,int size)
+{
+ spi_read(spi_g,buffer,size);
+}
+int modem_spi_write(char *buffer,int size)
+{
+ unsigned short *data = buffer;
+ spi_write(spi_g,buffer,size);
+}
+
+static int mux2spi_probe(struct spi_device *spi)
+{
+ int status;
+
+ spi_g = spi;
+ spi_g->mode = SPI_MODE_1;
+ spi_g->max_speed_hz = 1000000;
+ spi_g->bits_per_word = 32;
+
+ spi2_rx_buf_dma_virt =dma_alloc_coherent(NULL, 4096,&spi2_rx_buf_dma_phys, GFP_KERNEL | GFP_DMA);
+
+ if (spi2_rx_buf_dma_virt == NULL){
+ printk(KERN_ERR "spi2_rx_buf_dma_virt alloc fail");
+ return (-ENOMEM);
+ }
+
+ spi2_tx_buf_dma_virt =dma_alloc_coherent(NULL, 4096,&spi2_tx_buf_dma_phys, GFP_KERNEL | GFP_DMA);
+
+ if (spi2_tx_buf_dma_virt == NULL){
+ printk(KERN_ERR "spi2_tx_buf_dma_virt alloc fail");
+ return (-ENOMEM);
+ }
+
+ spin_lock_init(&write_spinlock);
+#ifdef SPI_WRITE_DEBUG
+ spin_lock_init(&log_spinlock);
+#endif
+ status = spi_setup(spi_g);
+
+ ret:
+ return status;
+}
+
+static struct spi_driver mux_spi_drv = {
+ .driver = {
+ .name = "spi_mux",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = mux2spi_probe,
+};
+
+
+static struct modem_device_operation spi_device_op = {
+ .dev = MODEM_DEV_SPI,
+ .open = modem_spi_open,
+ .read = modem_spi_read,
+ .write =modem_spi_write
+};
+struct modem_device_operation * modem_spi_drv_init(void)
+{
+ //sprd_spi_modem_device_register(0, NULL);
+ spi_g = NULL;
+ spi_register_driver(&mux_spi_drv);
+ return &spi_device_op;
+}
diff --git a/drivers/char/modem_interface/normal_mode.c b/drivers/char/modem_interface/normal_mode.c
new file mode 100644
index 00000000..5ab8fb5e
--- /dev/null
+++ b/drivers/char/modem_interface/normal_mode.c
@@ -0,0 +1,157 @@
+/*
+ * kernel/driver/char/modem_interface/normal_mode.c
+ *
+ * Generic modem interface GPIO handshake and dump memory process.
+ *
+ * Author: Jiayong Yang(Jiayong.Yang@spreadtrum.com)
+ * Created: Jul 27, 2012
+ * Copyright: Spreadtrum Inc.
+ *
+ * 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.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include "modem_buffer.h"
+#include "modem_interface_driver.h"
+
+extern size_t Read_modem_data_ext(const unsigned char * buf, unsigned short len);
+
+extern void modem_intf_set_mode(enum MODEM_Mode_type mode,int force);
+extern void modem_intf_ctrl_gpio_handle_bootcomp(int status);
+extern void modem_intf_ctrl_gpio_handle_dump(int status);
+extern void modem_intf_ctrl_gpio_handle_normal(int status);
+extern void modem_intf_reboot_routine(void);
+
+
+void shutdown_protocol(struct modem_message_node *msg)
+{
+ struct modem_intf_device * device;
+
+ if((msg == NULL)||(msg->parameter1==0))
+ return;
+
+ printk(KERN_INFO ">>shutdown entry message: %s \n",modem_intf_msg_string(msg->type));
+
+ device = (struct modem_intf_device *)msg->parameter1;
+
+ switch(msg->type) {
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = 0;
+ device->out_transfering = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void bootcomp_protocol(struct modem_message_node *msg)
+{
+ struct modem_intf_device * device;
+
+ if((msg == NULL)||(msg->parameter1==0))
+ return;
+
+ printk(KERN_INFO ">>bootcomp entry message: %s \n",modem_intf_msg_string(msg->type));
+
+ device = (struct modem_intf_device *)msg->parameter1;
+
+ switch(msg->type) {
+ case MODEM_CTRL_GPIO_CHG:
+ modem_intf_ctrl_gpio_handle_bootcomp(msg->parameter2);
+ break;
+ case MODEM_USER_REQ:
+ modem_intf_reboot_routine();
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = 0;
+ device->out_transfering = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+
+void dump_memory_protocol(struct modem_message_node *msg)
+{
+ struct modem_intf_device * device;
+
+ if((msg == NULL)||(msg->parameter1==0))
+ return;
+
+ printk(KERN_INFO ">>dump entry message: %s \n",modem_intf_msg_string(msg->type));
+
+ device = (struct modem_intf_device *)msg->parameter1;
+
+ switch(msg->type) {
+ case MODEM_CTRL_GPIO_CHG:
+ modem_intf_ctrl_gpio_handle_dump(msg->parameter2);
+ break;
+ case MODEM_USER_REQ:
+ modem_intf_reboot_routine();
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = 0;
+ device->out_transfering = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void reset_protocol(struct modem_message_node *msg)
+{
+ struct modem_intf_device * device;
+
+ if((msg == NULL)||(msg->parameter1==0))
+ return;
+
+ printk(KERN_INFO ">>reset entry message: %s \n",modem_intf_msg_string(msg->type));
+
+ device = (struct modem_intf_device *)msg->parameter1;
+
+ switch(msg->type) {
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = 0;
+ device->out_transfering = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+void normal_protocol(struct modem_message_node *msg)
+{
+ struct modem_intf_device * device;
+ if((msg == NULL)||(msg->parameter1==0))
+ return;
+
+ printk(KERN_INFO ">>normal entry message: %s \n",modem_intf_msg_string(msg->type));
+
+ device = (struct modem_intf_device *)msg->parameter1;
+
+ switch(msg->type) {
+ case MODEM_CTRL_GPIO_CHG:
+ modem_intf_ctrl_gpio_handle_normal(msg->parameter2);
+ break;
+ case MODEM_USER_REQ:
+ modem_intf_reboot_routine();
+ break;
+ case MODEM_SET_MODE:
+ modem_intf_set_mode(msg->parameter2, 1);
+ device->status = 0;
+ device->out_transfering = 0;
+ break;
+ default:
+ break;
+ }
+}