blob: cf51d172eaf4bcb8cca931d631815eb0a8f952d0 [file] [log] [blame]
/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*
* RPCROUTER SMD XPRT module.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/export.h>
#include <mach/msm_smd.h>
#include "smd_rpcrouter.h"
#include "smd_private.h"
struct rpcrouter_smd_xprt {
struct rpcrouter_xprt xprt;
smd_channel_t *channel;
};
static struct rpcrouter_smd_xprt smd_remote_xprt;
#ifdef CONFIG_ARCH_FSM9XXX
static struct rpcrouter_smd_xprt smd_remote_qdsp_xprt;
#endif
static int rpcrouter_smd_remote_read_avail(void)
{
return smd_read_avail(smd_remote_xprt.channel);
}
static int rpcrouter_smd_remote_read(void *data, uint32_t len)
{
return smd_read(smd_remote_xprt.channel, data, len);
}
static int rpcrouter_smd_remote_write_avail(void)
{
return smd_write_avail(smd_remote_xprt.channel);
}
static int rpcrouter_smd_remote_write(void *data, uint32_t len, uint32_t type)
{
return smd_write(smd_remote_xprt.channel, data, len);
}
static int rpcrouter_smd_remote_close(void)
{
smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
return smd_close(smd_remote_xprt.channel);
}
static void rpcrouter_smd_remote_notify(void *_dev, unsigned event)
{
switch (event) {
case SMD_EVENT_DATA:
msm_rpcrouter_xprt_notify(&smd_remote_xprt.xprt,
RPCROUTER_XPRT_EVENT_DATA);
break;
case SMD_EVENT_OPEN:
pr_info("%s: smd opened 0x%p\n", __func__, _dev);
msm_rpcrouter_xprt_notify(&smd_remote_xprt.xprt,
RPCROUTER_XPRT_EVENT_OPEN);
break;
case SMD_EVENT_CLOSE:
pr_info("%s: smd closed 0x%p\n", __func__, _dev);
msm_rpcrouter_xprt_notify(&smd_remote_xprt.xprt,
RPCROUTER_XPRT_EVENT_CLOSE);
break;
}
}
#ifdef CONFIG_ARCH_FSM9XXX
static int rpcrouter_smd_remote_qdsp_read_avail(void)
{
return smd_read_avail(smd_remote_qdsp_xprt.channel);
}
static int rpcrouter_smd_remote_qdsp_read(void *data, uint32_t len)
{
return smd_read(smd_remote_qdsp_xprt.channel, data, len);
}
static int rpcrouter_smd_remote_qdsp_write_avail(void)
{
return smd_write_avail(smd_remote_qdsp_xprt.channel);
}
static int rpcrouter_smd_remote_qdsp_write(void *data,
uint32_t len, uint32_t type)
{
return smd_write(smd_remote_qdsp_xprt.channel, data, len);
}
static int rpcrouter_smd_remote_qdsp_close(void)
{
/*
* TBD: Implement when we have N way SMSM ported
* smsm_change_state(SMSM_APPS_STATE, SMSM_RPCINIT, 0);
*/
return smd_close(smd_remote_qdsp_xprt.channel);
}
static void rpcrouter_smd_remote_qdsp_notify(void *_dev, unsigned event)
{
switch (event) {
case SMD_EVENT_DATA:
msm_rpcrouter_xprt_notify(&smd_remote_qdsp_xprt.xprt,
RPCROUTER_XPRT_EVENT_DATA);
break;
case SMD_EVENT_OPEN:
/* Print log info */
pr_debug("%s: smd opened\n", __func__);
msm_rpcrouter_xprt_notify(&smd_remote_qdsp_xprt.xprt,
RPCROUTER_XPRT_EVENT_OPEN);
break;
case SMD_EVENT_CLOSE:
/* Print log info */
pr_debug("%s: smd closed\n", __func__);
msm_rpcrouter_xprt_notify(&smd_remote_qdsp_xprt.xprt,
RPCROUTER_XPRT_EVENT_CLOSE);
break;
}
}
static int rpcrouter_smd_remote_qdsp_probe(struct platform_device *pdev)
{
int rc;
smd_remote_qdsp_xprt.xprt.name = "rpcrotuer_smd_qdsp_xprt";
smd_remote_qdsp_xprt.xprt.read_avail =
rpcrouter_smd_remote_qdsp_read_avail;
smd_remote_qdsp_xprt.xprt.read = rpcrouter_smd_remote_qdsp_read;
smd_remote_qdsp_xprt.xprt.write_avail =
rpcrouter_smd_remote_qdsp_write_avail;
smd_remote_qdsp_xprt.xprt.write = rpcrouter_smd_remote_qdsp_write;
smd_remote_qdsp_xprt.xprt.close = rpcrouter_smd_remote_qdsp_close;
smd_remote_qdsp_xprt.xprt.priv = NULL;
/* Open up SMD channel */
rc = smd_named_open_on_edge("RPCCALL_QDSP", SMD_APPS_QDSP,
&smd_remote_qdsp_xprt.channel, NULL,
rpcrouter_smd_remote_qdsp_notify);
if (rc < 0)
return rc;
smd_disable_read_intr(smd_remote_qdsp_xprt.channel);
return 0;
}
static struct platform_driver rpcrouter_smd_remote_qdsp_driver = {
.probe = rpcrouter_smd_remote_qdsp_probe,
.driver = {
.name = "RPCCALL_QDSP",
.owner = THIS_MODULE,
},
};
static inline int register_smd_remote_qpsp_driver(void)
{
return platform_driver_register(&rpcrouter_smd_remote_qdsp_driver);
}
#else /* CONFIG_ARCH_FSM9XXX */
static inline int register_smd_remote_qpsp_driver(void)
{
return 0;
}
#endif
#if defined(CONFIG_MSM_RPC_LOOPBACK_XPRT)
static struct rpcrouter_smd_xprt smd_loopback_xprt;
static int rpcrouter_smd_loopback_read_avail(void)
{
return smd_read_avail(smd_loopback_xprt.channel);
}
static int rpcrouter_smd_loopback_read(void *data, uint32_t len)
{
return smd_read(smd_loopback_xprt.channel, data, len);
}
static int rpcrouter_smd_loopback_write_avail(void)
{
return smd_write_avail(smd_loopback_xprt.channel);
}
static int rpcrouter_smd_loopback_write(void *data, uint32_t len, uint32 type)
{
return smd_write(smd_loopback_xprt.channel, data, len);
}
static int rpcrouter_smd_loopback_close(void)
{
return smd_close(smd_loopback_xprt.channel);
}
static void rpcrouter_smd_loopback_notify(void *_dev, unsigned event)
{
switch (event) {
case SMD_EVENT_DATA:
msm_rpcrouter_xprt_notify(&smd_loopback_xprt.xprt,
RPCROUTER_XPRT_EVENT_DATA);
break;
case SMD_EVENT_OPEN:
pr_debug("%s: smd loopback opened 0x%p\n", __func__, _dev);
msm_rpcrouter_xprt_notify(&smd_loopback_xprt.xprt,
RPCROUTER_XPRT_EVENT_OPEN);
break;
case SMD_EVENT_CLOSE:
pr_debug("%s: smd loopback closed 0x%p\n", __func__, _dev);
msm_rpcrouter_xprt_notify(&smd_loopback_xprt.xprt,
RPCROUTER_XPRT_EVENT_CLOSE);
break;
}
}
static int rpcrouter_smd_loopback_probe(struct platform_device *pdev)
{
int rc;
smd_loopback_xprt.xprt.name = "rpcrouter_loopback_xprt";
smd_loopback_xprt.xprt.read_avail = rpcrouter_smd_loopback_read_avail;
smd_loopback_xprt.xprt.read = rpcrouter_smd_loopback_read;
smd_loopback_xprt.xprt.write_avail = rpcrouter_smd_loopback_write_avail;
smd_loopback_xprt.xprt.write = rpcrouter_smd_loopback_write;
smd_loopback_xprt.xprt.close = rpcrouter_smd_loopback_close;
smd_loopback_xprt.xprt.priv = NULL;
/* Open up SMD LOOPBACK channel */
rc = smd_named_open_on_edge("local_loopback", SMD_LOOPBACK_TYPE,
&smd_loopback_xprt.channel, NULL,
rpcrouter_smd_loopback_notify);
if (rc < 0)
return rc;
smd_disable_read_intr(smd_remote_xprt.channel);
return 0;
}
static struct platform_driver rpcrouter_smd_loopback_driver = {
.probe = rpcrouter_smd_loopback_probe,
.driver = {
.name = "local_loopback",
.owner = THIS_MODULE,
},
};
static inline int register_smd_loopback_driver(void)
{
return platform_driver_register(&rpcrouter_smd_loopback_driver);
}
#else /* CONFIG_MSM_RPC_LOOPBACK_XPRT */
static inline int register_smd_loopback_driver(void)
{
return 0;
}
#endif
static int rpcrouter_smd_remote_probe(struct platform_device *pdev)
{
int rc;
smd_remote_xprt.xprt.name = "rpcrotuer_smd_xprt";
smd_remote_xprt.xprt.read_avail = rpcrouter_smd_remote_read_avail;
smd_remote_xprt.xprt.read = rpcrouter_smd_remote_read;
smd_remote_xprt.xprt.write_avail = rpcrouter_smd_remote_write_avail;
smd_remote_xprt.xprt.write = rpcrouter_smd_remote_write;
smd_remote_xprt.xprt.close = rpcrouter_smd_remote_close;
smd_remote_xprt.xprt.priv = NULL;
/* Open up SMD channel */
rc = smd_open("RPCCALL", &smd_remote_xprt.channel, NULL,
rpcrouter_smd_remote_notify);
if (rc < 0)
return rc;
smd_disable_read_intr(smd_remote_xprt.channel);
return 0;
}
static struct platform_driver rpcrouter_smd_remote_driver = {
.probe = rpcrouter_smd_remote_probe,
.driver = {
.name = "RPCCALL",
.owner = THIS_MODULE,
},
};
static int __init rpcrouter_smd_init(void)
{
int rc;
rc = register_smd_loopback_driver();
if (rc < 0)
return rc;
rc = register_smd_remote_qpsp_driver();
if (rc < 0)
return rc;
return platform_driver_register(&rpcrouter_smd_remote_driver);
}
module_init(rpcrouter_smd_init);
MODULE_DESCRIPTION("RPC Router SMD XPRT");
MODULE_LICENSE("GPL v2");