230 lines
5.6 KiB
C
230 lines
5.6 KiB
C
/* arch/arm/mach-msm/rpc_servers.c
|
|
*
|
|
* Copyright (C) 2007 Google, Inc.
|
|
* Author: Iliyan Malchev <ibm@android.com>
|
|
*
|
|
* 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/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/init.h>
|
|
#include <linux/device.h>
|
|
#include <linux/types.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/wakelock.h>
|
|
|
|
#include <linux/msm_rpcrouter.h>
|
|
#include <linux/uaccess.h>
|
|
|
|
#include <mach/msm_rpcrouter.h>
|
|
#include "smd_rpcrouter.h"
|
|
|
|
static struct msm_rpc_endpoint *endpoint;
|
|
|
|
#define FLAG_REGISTERED 0x0001
|
|
|
|
static LIST_HEAD(rpc_server_list);
|
|
static DEFINE_MUTEX(rpc_server_list_lock);
|
|
static int rpc_servers_active;
|
|
static struct wake_lock rpc_servers_wake_lock;
|
|
|
|
static void rpc_server_register(struct msm_rpc_server *server)
|
|
{
|
|
int rc;
|
|
rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
|
|
if (rc < 0)
|
|
printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
|
|
server, server->prog, server->vers);
|
|
}
|
|
|
|
static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
|
|
{
|
|
struct msm_rpc_server *server;
|
|
|
|
mutex_lock(&rpc_server_list_lock);
|
|
list_for_each_entry(server, &rpc_server_list, list) {
|
|
if ((server->prog == prog) &&
|
|
#if CONFIG_MSM_AMSS_VERSION >= 6350 || defined(CONFIG_ARCH_QSD8X50)
|
|
msm_rpc_is_compatible_version(server->vers, vers)) {
|
|
#else
|
|
server->vers == vers) {
|
|
#endif
|
|
mutex_unlock(&rpc_server_list_lock);
|
|
return server;
|
|
}
|
|
}
|
|
mutex_unlock(&rpc_server_list_lock);
|
|
return NULL;
|
|
}
|
|
|
|
static void rpc_server_register_all(void)
|
|
{
|
|
struct msm_rpc_server *server;
|
|
|
|
mutex_lock(&rpc_server_list_lock);
|
|
list_for_each_entry(server, &rpc_server_list, list) {
|
|
if (!(server->flags & FLAG_REGISTERED)) {
|
|
rpc_server_register(server);
|
|
server->flags |= FLAG_REGISTERED;
|
|
}
|
|
}
|
|
mutex_unlock(&rpc_server_list_lock);
|
|
}
|
|
|
|
int msm_rpc_create_server(struct msm_rpc_server *server)
|
|
{
|
|
/* make sure we're in a sane state first */
|
|
server->flags = 0;
|
|
INIT_LIST_HEAD(&server->list);
|
|
|
|
mutex_lock(&rpc_server_list_lock);
|
|
list_add(&server->list, &rpc_server_list);
|
|
if (rpc_servers_active) {
|
|
rpc_server_register(server);
|
|
server->flags |= FLAG_REGISTERED;
|
|
}
|
|
mutex_unlock(&rpc_server_list_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
|
|
uint32_t xid, uint32_t accept_status)
|
|
{
|
|
int rc = 0;
|
|
uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
|
|
struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
|
|
|
|
reply->xid = cpu_to_be32(xid);
|
|
reply->type = cpu_to_be32(1); /* reply */
|
|
reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
|
|
|
|
reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
|
|
reply->data.acc_hdr.verf_flavor = 0;
|
|
reply->data.acc_hdr.verf_length = 0;
|
|
|
|
rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
|
|
if (rc < 0)
|
|
printk(KERN_ERR
|
|
"%s: could not write response: %d\n",
|
|
__FUNCTION__, rc);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int rpc_servers_thread(void *data)
|
|
{
|
|
void *buffer;
|
|
struct rpc_request_hdr *req;
|
|
struct msm_rpc_server *server;
|
|
int rc;
|
|
|
|
for (;;) {
|
|
wake_unlock(&rpc_servers_wake_lock);
|
|
rc = wait_event_interruptible(endpoint->wait_q,
|
|
!list_empty(&endpoint->read_q));
|
|
wake_lock(&rpc_servers_wake_lock);
|
|
rc = msm_rpc_read(endpoint, &buffer, -1, -1);
|
|
if (rc < 0) {
|
|
printk(KERN_ERR "%s: could not read: %d\n",
|
|
__FUNCTION__, rc);
|
|
break;
|
|
}
|
|
req = (struct rpc_request_hdr *)buffer;
|
|
|
|
req->type = be32_to_cpu(req->type);
|
|
req->xid = be32_to_cpu(req->xid);
|
|
req->rpc_vers = be32_to_cpu(req->rpc_vers);
|
|
req->prog = be32_to_cpu(req->prog);
|
|
req->vers = be32_to_cpu(req->vers);
|
|
req->procedure = be32_to_cpu(req->procedure);
|
|
|
|
server = rpc_server_find(req->prog, req->vers);
|
|
|
|
if (req->rpc_vers != 2)
|
|
continue;
|
|
if (req->type != 0)
|
|
continue;
|
|
if (!server) {
|
|
rpc_send_accepted_void_reply(
|
|
endpoint, req->xid,
|
|
RPC_ACCEPTSTAT_PROG_UNAVAIL);
|
|
continue;
|
|
}
|
|
|
|
rc = server->rpc_call(server, req, rc);
|
|
|
|
switch (rc) {
|
|
case 0:
|
|
rpc_send_accepted_void_reply(
|
|
endpoint, req->xid,
|
|
RPC_ACCEPTSTAT_SUCCESS);
|
|
break;
|
|
default:
|
|
rpc_send_accepted_void_reply(
|
|
endpoint, req->xid,
|
|
RPC_ACCEPTSTAT_PROG_UNAVAIL);
|
|
break;
|
|
}
|
|
|
|
kfree(buffer);
|
|
}
|
|
|
|
do_exit(0);
|
|
}
|
|
|
|
static int rpcservers_probe(struct platform_device *pdev)
|
|
{
|
|
struct task_struct *server_thread;
|
|
|
|
endpoint = msm_rpc_open();
|
|
if (IS_ERR(endpoint))
|
|
return PTR_ERR(endpoint);
|
|
|
|
/* we're online -- register any servers installed beforehand */
|
|
rpc_servers_active = 1;
|
|
rpc_server_register_all();
|
|
|
|
/* start the kernel thread */
|
|
server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
|
|
if (IS_ERR(server_thread))
|
|
return PTR_ERR(server_thread);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver rpcservers_driver = {
|
|
.probe = rpcservers_probe,
|
|
.driver = {
|
|
.name = "oncrpc_router",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
static int __init rpc_servers_init(void)
|
|
{
|
|
wake_lock_init(&rpc_servers_wake_lock, WAKE_LOCK_SUSPEND, "rpc_server");
|
|
return platform_driver_register(&rpcservers_driver);
|
|
}
|
|
|
|
module_init(rpc_servers_init);
|
|
|
|
MODULE_DESCRIPTION("MSM RPC Servers");
|
|
MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
|
|
MODULE_LICENSE("GPL");
|