aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/modem_if/sipc4_io_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/modem_if/sipc4_io_device.c')
-rw-r--r--drivers/misc/modem_if/sipc4_io_device.c311
1 files changed, 105 insertions, 206 deletions
diff --git a/drivers/misc/modem_if/sipc4_io_device.c b/drivers/misc/modem_if/sipc4_io_device.c
index 28f95f7..da1ea04 100644
--- a/drivers/misc/modem_if/sipc4_io_device.c
+++ b/drivers/misc/modem_if/sipc4_io_device.c
@@ -1,6 +1,4 @@
-/* /linux/drivers/misc/modem_if/modem_io_device.c
- *
- * Copyright (C) 2010 Google, Inc.
+/*
* Copyright (C) 2010 Samsung Electronics.
*
* This software is licensed under the terms of the GNU General Public
@@ -26,10 +24,7 @@
#include <linux/etherdevice.h>
#include <linux/device.h>
-#include <linux/platform_data/modem.h>
-#ifdef CONFIG_LINK_DEVICE_C2C
-#include <linux/platform_data/c2c.h>
-#endif
+#include "modem.h"
#include "modem_prj.h"
#include "modem_utils.h"
@@ -40,7 +35,8 @@
* So, give restriction to allocation size below 1 page to prevent
* big pages broken.
*/
-#define MAX_RXDATA_SIZE 0x0E00 /* 4 * 1024 - 512 */
+#define MAX_RXDATA_SIZE (4096 - 512)
+#define MAX_BOOTDATA_SIZE 0x4008 /* EBL package format*/
#define MAX_MULTI_FMT_SIZE 0x4000 /* 16 * 1024 */
static const char hdlc_start[1] = { HDLC_START };
@@ -250,22 +246,6 @@ static int rx_hdlc_head_check(struct io_device *iod, struct link_device *ld,
hdr->start = HDLC_START;
hdr->len = 0;
- /* debug print */
- switch (iod->format) {
- case IPC_FMT:
- case IPC_RAW:
- case IPC_MULTI_RAW:
- case IPC_RFS:
- /* TODO: print buf... */
- break;
-
- case IPC_CMD:
- case IPC_BOOT:
- case IPC_RAMDUMP:
- default:
- break;
- }
-
buf += len;
done_len += len;
rest -= len; /* rest, call by value */
@@ -409,12 +389,6 @@ static int rx_multi_fmt_frame(struct sk_buff *rx_skb)
/* If there has been no multiple frame with this ID */
if (!(fh->control & 0x80)) {
/* It is a single frame because the "more" bit is 0. */
-#if 0
- mif_err("\n<%s> Rx FMT frame (len %d)\n",
- iod->name, rcvd);
- print_sipc4_fmt_frame(data);
- mif_err("\n");
-#endif
skb_queue_tail(&iod->sk_rx_q,
fragdata(iod, ld)->skb_recv);
mif_debug("wake up wq of %s\n", iod->name);
@@ -449,12 +423,6 @@ static int rx_multi_fmt_frame(struct sk_buff *rx_skb)
/* It is the last frame because the "more" bit is 0. */
mif_info("The Last (ID %d, %d bytes received)\n",
id, skb->len);
-#if 0
- mif_err("\n<%s> Rx FMT frame (len %d)\n",
- iod->name, skb->len);
- print_sipc4_fmt_frame(skb->data);
- mif_err("\n");
-#endif
skb_queue_tail(&iod->sk_rx_q, skb);
iod->skb[id] = NULL;
mif_info("wake up wq of %s\n", iod->name);
@@ -491,12 +459,6 @@ static int rx_multi_fmt_frame_sipc42(struct sk_buff *rx_skb)
/* If there has been no multiple frame with this ID */
if (!(fh->control & 0x80)) {
/* It is a single frame because the "more" bit is 0. */
-#if 0
- mif_err("\n<%s> Rx FMT frame (len %d)\n",
- iod->name, rcvd);
- print_sipc4_fmt_frame(data);
- mif_err("\n");
-#endif
skb_queue_tail(&real_iod->sk_rx_q,
fragdata(iod, ld)->skb_recv);
mif_debug("wake up wq of %s\n", iod->name);
@@ -530,12 +492,6 @@ static int rx_multi_fmt_frame_sipc42(struct sk_buff *rx_skb)
/* It is the last frame because the "more" bit is 0. */
mif_err("The Last (ID %d, %d bytes received)\n",
id, skb->len);
-#if 0
- mif_err("\n<%s> Rx FMT frame (len %d)\n",
- iod->name, skb->len);
- print_sipc4_fmt_frame(skb->data);
- mif_err("\n");
-#endif
skb_queue_tail(&real_iod->sk_rx_q, skb);
real_iod->skb[id] = NULL;
mif_info("wake up wq of %s\n", real_iod->name);
@@ -819,55 +775,6 @@ exit:
return err;
}
-static int rx_rfs_packet(struct io_device *iod, struct link_device *ld,
- const char *data, unsigned size)
-{
- int err = 0;
- int pad = 0;
- int rcvd = 0;
- struct sk_buff *skb;
-
- if (data[0] != HDLC_START) {
- mif_err("Dropping RFS packet ... "
- "size = %d, start = %02X %02X %02X %02X\n",
- size,
- data[0], data[1], data[2], data[3]);
- return -EINVAL;
- }
-
- if (data[size-1] != HDLC_END) {
- for (pad = 1; pad < 4; pad++)
- if (data[(size-1)-pad] == HDLC_END)
- break;
-
- if (pad >= 4) {
- char *b = (char *)data;
- unsigned sz = size;
- mif_err("size %d, No END_FLAG!!!\n", size);
- mif_err("end = %02X %02X %02X %02X\n",
- b[sz-4], b[sz-3], b[sz-2], b[sz-1]);
- return -EINVAL;
- } else {
- mif_info("padding = %d\n", pad);
- }
- }
-
- skb = rx_alloc_skb(size, iod, ld);
- if (unlikely(!skb)) {
- mif_err("alloc_skb fail\n");
- return -ENOMEM;
- }
-
- /* copy the RFS haeder to skb->data */
- rcvd = size - sizeof(hdlc_start) - sizeof(hdlc_end) - pad;
- memcpy(skb_put(skb, rcvd), ((char *)data + sizeof(hdlc_start)), rcvd);
-
- fragdata(iod, ld)->skb_recv = skb;
- err = rx_iodev_skb(fragdata(iod, ld)->skb_recv);
-
- return err;
-}
-
/* called from link device when a packet arrives for this io device */
static int io_dev_recv_data_from_link_dev(struct io_device *iod,
struct link_device *ld, const char *data, unsigned int len)
@@ -891,14 +798,9 @@ static int io_dev_recv_data_from_link_dev(struct io_device *iod,
*/
switch (iod->format) {
- case IPC_RFS:
-#ifdef CONFIG_IPC_CMC22x_OLD_RFS
- err = rx_rfs_packet(iod, ld, data, len);
- return err;
-#endif
-
case IPC_FMT:
case IPC_RAW:
+ case IPC_RFS:
case IPC_MULTI_RAW:
if (iod->waketime)
wake_lock_timeout(&iod->wakelock, iod->waketime);
@@ -961,12 +863,17 @@ static int io_dev_recv_data_from_link_dev(struct io_device *iod,
static void io_dev_modem_state_changed(struct io_device *iod,
enum modem_state state)
{
- iod->mc->phone_state = state;
- mif_err("modem state changed. (iod: %s, state: %d)\n",
- iod->name, state);
+ struct modem_ctl *mc = iod->mc;
+ int old_state = mc->phone_state;
- if ((state == STATE_CRASH_RESET) || (state == STATE_CRASH_EXIT)
- || (state == STATE_NV_REBUILDING))
+ if (old_state != state) {
+ mc->phone_state = state;
+ mif_err("%s state changed (%s -> %s)\n", mc->name,
+ get_cp_state_str(old_state), get_cp_state_str(state));
+ }
+
+ if (state == STATE_CRASH_RESET || state == STATE_CRASH_EXIT ||
+ state == STATE_NV_REBUILDING)
wake_up(&iod->wq);
}
@@ -977,10 +884,24 @@ static void io_dev_modem_state_changed(struct io_device *iod,
*/
static void io_dev_sim_state_changed(struct io_device *iod, bool sim_online)
{
+
+#if defined(CONFIG_MACH_KONA) && defined(CONFIG_UMTS_MODEM_XMM6262)
+ mif_err("modem_current_state is %d\n", iod->mc->phone_state);
+#endif
+
if (atomic_read(&iod->opened) == 0) {
- mif_err("iod is not opened: %s\n",
- iod->name);
- } else if (iod->mc->sim_state.online == sim_online) {
+ mif_err("iod is not opened: %s\n", iod->name);
+ /* update latest sim status */
+ iod->mc->sim_state.online = sim_online;
+ }
+#if defined(CONFIG_LINK_DEVICE_HSIC) && defined(CONFIG_UMTS_MODEM_XMM6262) // fixed modem unknown issue (kina 3G)
+ else if (iod->mc->phone_state == STATE_BOOTING) {
+ mif_err("modem_current_state is STATE_BOOTING\n");
+ /* update latest sim status */
+ iod->mc->sim_state.online = sim_online;
+ }
+#endif
+ else if (iod->mc->sim_state.online == sim_online) {
mif_err("sim state not changed.\n");
} else {
iod->mc->sim_state.online = sim_online;
@@ -995,6 +916,7 @@ static void io_dev_sim_state_changed(struct io_device *iod, bool sim_online)
}
}
+
static int misc_open(struct inode *inode, struct file *filp)
{
struct io_device *iod = to_io_device(filp->private_data);
@@ -1078,32 +1000,32 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
switch (cmd) {
case IOCTL_MODEM_ON:
- mif_debug("misc_ioctl : IOCTL_MODEM_ON\n");
+ mif_debug("%s: IOCTL_MODEM_ON\n", iod->name);
return iod->mc->ops.modem_on(iod->mc);
case IOCTL_MODEM_OFF:
- mif_debug("misc_ioctl : IOCTL_MODEM_OFF\n");
+ mif_debug("%s: IOCTL_MODEM_OFF\n", iod->name);
return iod->mc->ops.modem_off(iod->mc);
case IOCTL_MODEM_RESET:
- mif_debug("misc_ioctl : IOCTL_MODEM_RESET\n");
+ mif_debug("%s: IOCTL_MODEM_RESET\n", iod->name);
return iod->mc->ops.modem_reset(iod->mc);
case IOCTL_MODEM_BOOT_ON:
- mif_debug("misc_ioctl : IOCTL_MODEM_BOOT_ON\n");
+ mif_debug("%s: IOCTL_MODEM_BOOT_ON\n", iod->name);
return iod->mc->ops.modem_boot_on(iod->mc);
case IOCTL_MODEM_BOOT_OFF:
- mif_debug("misc_ioctl : IOCTL_MODEM_BOOT_OFF\n");
+ mif_debug("%s: IOCTL_MODEM_BOOT_OFF\n", iod->name);
return iod->mc->ops.modem_boot_off(iod->mc);
/* TODO - will remove this command after ril updated */
case IOCTL_MODEM_BOOT_DONE:
- mif_debug("misc_ioctl : IOCTL_MODEM_BOOT_DONE\n");
+ mif_debug("%s: IOCTL_MODEM_BOOT_DONE\n", iod->name);
return 0;
case IOCTL_MODEM_STATUS:
- mif_debug("misc_ioctl : IOCTL_MODEM_STATUS\n");
+ mif_debug("%s: IOCTL_MODEM_STATUS\n", iod->name);
p_state = iod->mc->phone_state;
if ((p_state == STATE_CRASH_RESET) ||
@@ -1126,7 +1048,7 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return p_state;
case IOCTL_MODEM_PROTOCOL_SUSPEND:
- mif_info("misc_ioctl : IOCTL_MODEM_PROTOCOL_SUSPEND\n");
+ mif_info("%s: IOCTL_MODEM_PROTOCOL_SUSPEND\n", iod->name);
if (iod->format != IPC_MULTI_RAW)
return -EINVAL;
@@ -1134,8 +1056,16 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
iodevs_for_each(iod->msd, iodev_netif_stop, 0);
return 0;
+ case IOCTL_MODEM_DL_START:
+ mif_info("%s: IOCTL_MODEM_DL_START\n", iod->name);
+ return ld->dload_start(ld, iod);
+
+ case IOCTL_MODEM_FW_UPDATE:
+ mif_info("%s: IOCTL_MODEM_FW_UPDATE\n", iod->name);
+ return ld->firm_update(ld, iod, arg);
+
case IOCTL_MODEM_PROTOCOL_RESUME:
- mif_info("misc_ioctl : IOCTL_MODEM_PROTOCOL_RESUME\n");
+ mif_info("%s: IOCTL_MODEM_PROTOCOL_RESUME\n", iod->name);
if (iod->format != IPC_MULTI_RAW)
return -EINVAL;
@@ -1144,21 +1074,29 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return 0;
case IOCTL_MODEM_DUMP_START:
- mif_err("misc_ioctl : IOCTL_MODEM_DUMP_START\n");
+ mif_err("%s: IOCTL_MODEM_DUMP_START\n", iod->name);
+ return ld->dump_start(ld, iod);
+
+ case IOCTL_MODEM_RAMDUMP_START:
+ mif_err("%s: IOCTL_MODEM_RAMDUMP_START\n", iod->name);
return ld->dump_start(ld, iod);
case IOCTL_MODEM_DUMP_UPDATE:
- mif_debug("misc_ioctl : IOCTL_MODEM_DUMP_UPDATE\n");
+ mif_debug("%s: IOCTL_MODEM_DUMP_UPDATE\n", iod->name);
return ld->dump_update(ld, iod, arg);
+ case IOCTL_MODEM_RAMDUMP_STOP:
+ mif_info("%s: IOCTL_MODEM_RAMDUMP_STOP\n", iod->name);
+ return ld->dump_finish(ld, iod, arg);
+
case IOCTL_MODEM_FORCE_CRASH_EXIT:
- mif_debug("misc_ioctl : IOCTL_MODEM_FORCE_CRASH_EXIT\n");
+ mif_debug("%s: IOCTL_MODEM_FORCE_CRASH_EXIT\n", iod->name);
if (iod->mc->ops.modem_force_crash_exit)
return iod->mc->ops.modem_force_crash_exit(iod->mc);
return -EINVAL;
case IOCTL_MODEM_CP_UPLOAD:
- mif_err("misc_ioctl : IOCTL_MODEM_CP_UPLOAD\n");
+ mif_err("%s: IOCTL_MODEM_CP_UPLOAD\n", iod->name);
if (copy_from_user(cpinfo_buf + strlen(cpinfo_buf),
(void __user *)arg, MAX_CPINFO_SIZE) != 0)
panic("CP Crash");
@@ -1167,12 +1105,12 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return 0;
case IOCTL_MODEM_DUMP_RESET:
- mif_err("misc_ioctl : IOCTL_MODEM_DUMP_RESET\n");
+ mif_err("%s: IOCTL_MODEM_DUMP_RESET\n", iod->name);
return iod->mc->ops.modem_dump_reset(iod->mc);
#if defined(CONFIG_SEC_DUAL_MODEM_MODE)
case IOCTL_MODEM_SWITCH_MODEM:
- mif_err("misc_ioctl : IOCTL_MODEM_SWITCH_MODEM\n");
+ mif_err("%s: IOCTL_MODEM_SWITCH_MODEM\n", iod->name);
iod->mc->phone_state = STATE_MODEM_SWITCH;
wake_up(&iod->wq);
return 0;
@@ -1188,20 +1126,6 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
mif_dump_log(iod->mc->msd, iod);
return 0;
- case IOCTL_MIF_DPRAM_DUMP:
-#ifdef CONFIG_LINK_DEVICE_DPRAM
- if (iod->mc->mdm_data->link_types & LINKTYPE(LINKDEV_DPRAM)) {
- size = iod->mc->mdm_data->dpram_ctl->dp_size;
- ret = copy_to_user((void __user *)arg, &size,
- sizeof(unsigned long));
- if (ret < 0)
- return -EFAULT;
- mif_dump_dpram(iod);
- return 0;
- }
-#endif
- return -EINVAL;
-
default:
/* If you need to handle the ioctl for specific link device,
* then assign the link ioctl handler to ld->ioctl
@@ -1209,12 +1133,48 @@ static long misc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (ld->ioctl)
return ld->ioctl(ld, iod, cmd, arg);
- mif_err("misc_ioctl : ioctl 0x%X is not defined.\n", cmd);
+ mif_err("%s: ioctl 0x%X is not defined\n", iod->name, cmd);
return -EINVAL;
}
return 0;
}
+static size_t _boot_write(struct io_device *iod, const char __user *buf,
+ size_t count)
+{
+ int rest_len = count, frame_len = 0;
+ char *cur = (char *)buf;
+ struct sk_buff *skb = NULL;
+ struct link_device *ld = get_current_link(iod);
+ int ret;
+
+ while (rest_len) {
+ frame_len = min(rest_len, MAX_BOOTDATA_SIZE);
+ skb = alloc_skb(frame_len, GFP_KERNEL);
+ if (!skb) {
+ mif_err("fail alloc skb (%d)\n", __LINE__);
+ return -ENOMEM;
+ }
+ if (copy_from_user(
+ skb_put(skb, frame_len), cur, frame_len) != 0) {
+ dev_kfree_skb_any(skb);
+ return -EFAULT;
+ }
+ rest_len -= frame_len;
+ cur += frame_len;
+
+ skbpriv(skb)->iod = iod;
+ skbpriv(skb)->ld = ld;
+
+ ret = ld->send(ld, iod, skb);
+ if (ret < 0) {
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+ }
+ return count;
+}
+
static ssize_t misc_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -1237,6 +1197,10 @@ static ssize_t misc_write(struct file *filp, const char __user *buf,
skb = alloc_skb(frame_len, GFP_KERNEL);
if (!skb) {
+ if (frame_len > MAX_BOOTDATA_SIZE && iod->format == IPC_BOOT) {
+ mif_info("large alloc fail\n");
+ return _boot_write(iod, buf, count);
+ }
mif_err("fail alloc skb (%d)\n", __LINE__);
return -ENOMEM;
}
@@ -1278,31 +1242,6 @@ static ssize_t misc_write(struct file *filp, const char __user *buf,
skb_put(skb, calc_padding_size(iod, ld, skb->len));
-#if 0
- if (iod->format == IPC_FMT) {
- mif_err("\n<%s> Tx HDLC FMT frame (len %d)\n",
- iod->name, skb->len);
- print_sipc4_hdlc_fmt_frame(skb->data);
- mif_err("\n");
- }
-#endif
-#if 0
- if (iod->format == IPC_RAW) {
- mif_err("\n<%s> Tx HDLC RAW frame (len %d)\n",
- iod->name, skb->len);
- mif_print_data(skb->data, (skb->len < 64 ? skb->len : 64));
- mif_err("\n");
- }
-#endif
-#if 0
- if (iod->format == IPC_RFS) {
- mif_err("\n<%s> Tx HDLC RFS frame (len %d)\n",
- iod->name, skb->len);
- mif_print_data(skb->data, (skb->len < 64 ? skb->len : 64));
- mif_err("\n");
- }
-#endif
-
/* send data with sk_buff, link device will put sk_buff
* into the specific sk_buff_q and run work-q to send data
*/
@@ -1409,43 +1348,6 @@ static ssize_t misc_read(struct file *filp, char *buf, size_t count,
return pktsize;
}
-#ifdef CONFIG_LINK_DEVICE_C2C
-static int misc_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- int r = 0;
- unsigned long size = 0;
- unsigned long pfn = 0;
- unsigned long offset = 0;
- struct io_device *iod = (struct io_device *)filp->private_data;
-
- if (!vma)
- return -EFAULT;
-
- size = vma->vm_end - vma->vm_start;
- offset = vma->vm_pgoff << PAGE_SHIFT;
- if (offset + size > (C2C_CP_RGN_SIZE + C2C_SH_RGN_SIZE)) {
- mif_err("offset + size > C2C_CP_RGN_SIZE\n");
- return -EINVAL;
- }
-
- /* Set the noncacheable property to the region */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- vma->vm_flags |= VM_RESERVED | VM_IO;
-
- pfn = __phys_to_pfn(C2C_CP_RGN_ADDR + offset);
- r = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
- if (r) {
- mif_err("Failed in remap_pfn_range()!!!\n");
- return -EAGAIN;
- }
-
- mif_err("VA = 0x%08lx, offset = 0x%lx, size = %lu\n",
- vma->vm_start, offset, size);
-
- return 0;
-}
-#endif
-
static const struct file_operations misc_io_fops = {
.owner = THIS_MODULE,
.open = misc_open,
@@ -1454,9 +1356,6 @@ static const struct file_operations misc_io_fops = {
.unlocked_ioctl = misc_ioctl,
.write = misc_write,
.read = misc_read,
-#ifdef CONFIG_LINK_DEVICE_C2C
- .mmap = misc_mmap,
-#endif
};
static int vnet_open(struct net_device *ndev)