linux/drivers/staging/dream/smd/smd_rpcrouter_servers.c
<<
>>
Prefs
   1/* arch/arm/mach-msm/rpc_servers.c
   2 *
   3 * Copyright (C) 2007 Google, Inc.
   4 * Author: Iliyan Malchev <ibm@android.com>
   5 *
   6 * This software is licensed under the terms of the GNU General Public
   7 * License version 2, as published by the Free Software Foundation, and
   8 * may be copied, distributed, and modified under those terms.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/kernel.h>
  19#include <linux/string.h>
  20#include <linux/errno.h>
  21#include <linux/cdev.h>
  22#include <linux/init.h>
  23#include <linux/device.h>
  24#include <linux/types.h>
  25#include <linux/fs.h>
  26#include <linux/kthread.h>
  27#include <linux/delay.h>
  28#include <linux/platform_device.h>
  29#include <linux/wakelock.h>
  30
  31#include <linux/msm_rpcrouter.h>
  32#include <linux/uaccess.h>
  33
  34#include <mach/msm_rpcrouter.h>
  35#include "smd_rpcrouter.h"
  36
  37static struct msm_rpc_endpoint *endpoint;
  38
  39#define FLAG_REGISTERED 0x0001
  40
  41static LIST_HEAD(rpc_server_list);
  42static DEFINE_MUTEX(rpc_server_list_lock);
  43static int rpc_servers_active;
  44static struct wake_lock rpc_servers_wake_lock;
  45
  46static void rpc_server_register(struct msm_rpc_server *server)
  47{
  48        int rc;
  49        rc = msm_rpc_register_server(endpoint, server->prog, server->vers);
  50        if (rc < 0)
  51                printk(KERN_ERR "[rpcserver] error registering %p @ %08x:%d\n",
  52                       server, server->prog, server->vers);
  53}
  54
  55static struct msm_rpc_server *rpc_server_find(uint32_t prog, uint32_t vers)
  56{
  57        struct msm_rpc_server *server;
  58
  59        mutex_lock(&rpc_server_list_lock);
  60        list_for_each_entry(server, &rpc_server_list, list) {
  61                if ((server->prog == prog) &&
  62#if CONFIG_MSM_AMSS_VERSION >= 6350
  63                    msm_rpc_is_compatible_version(server->vers, vers)) {
  64#else
  65                    server->vers == vers) {
  66#endif
  67                        mutex_unlock(&rpc_server_list_lock);
  68                        return server;
  69                }
  70        }
  71        mutex_unlock(&rpc_server_list_lock);
  72        return NULL;
  73}
  74
  75static void rpc_server_register_all(void)
  76{
  77        struct msm_rpc_server *server;
  78
  79        mutex_lock(&rpc_server_list_lock);
  80        list_for_each_entry(server, &rpc_server_list, list) {
  81                if (!(server->flags & FLAG_REGISTERED)) {
  82                        rpc_server_register(server);
  83                        server->flags |= FLAG_REGISTERED;
  84                }
  85        }
  86        mutex_unlock(&rpc_server_list_lock);
  87}
  88
  89int msm_rpc_create_server(struct msm_rpc_server *server)
  90{
  91        /* make sure we're in a sane state first */
  92        server->flags = 0;
  93        INIT_LIST_HEAD(&server->list);
  94
  95        mutex_lock(&rpc_server_list_lock);
  96        list_add(&server->list, &rpc_server_list);
  97        if (rpc_servers_active) {
  98                rpc_server_register(server);
  99                server->flags |= FLAG_REGISTERED;
 100        }
 101        mutex_unlock(&rpc_server_list_lock);
 102
 103        return 0;
 104}
 105
 106static int rpc_send_accepted_void_reply(struct msm_rpc_endpoint *client,
 107                                        uint32_t xid, uint32_t accept_status)
 108{
 109        int rc = 0;
 110        uint8_t reply_buf[sizeof(struct rpc_reply_hdr)];
 111        struct rpc_reply_hdr *reply = (struct rpc_reply_hdr *)reply_buf;
 112
 113        reply->xid = cpu_to_be32(xid);
 114        reply->type = cpu_to_be32(1); /* reply */
 115        reply->reply_stat = cpu_to_be32(RPCMSG_REPLYSTAT_ACCEPTED);
 116
 117        reply->data.acc_hdr.accept_stat = cpu_to_be32(accept_status);
 118        reply->data.acc_hdr.verf_flavor = 0;
 119        reply->data.acc_hdr.verf_length = 0;
 120
 121        rc = msm_rpc_write(client, reply_buf, sizeof(reply_buf));
 122        if (rc < 0)
 123                printk(KERN_ERR
 124                       "%s: could not write response: %d\n",
 125                       __FUNCTION__, rc);
 126
 127        return rc;
 128}
 129
 130static int rpc_servers_thread(void *data)
 131{
 132        void *buffer;
 133        struct rpc_request_hdr *req;
 134        struct msm_rpc_server *server;
 135        int rc;
 136
 137        for (;;) {
 138                wake_unlock(&rpc_servers_wake_lock);
 139                rc = wait_event_interruptible(endpoint->wait_q,
 140                                                !list_empty(&endpoint->read_q));
 141                wake_lock(&rpc_servers_wake_lock);
 142                rc = msm_rpc_read(endpoint, &buffer, -1, -1);
 143                if (rc < 0) {
 144                        printk(KERN_ERR "%s: could not read: %d\n",
 145                               __FUNCTION__, rc);
 146                        break;
 147                }
 148                req = (struct rpc_request_hdr *)buffer;
 149
 150                req->type = be32_to_cpu(req->type);
 151                req->xid = be32_to_cpu(req->xid);
 152                req->rpc_vers = be32_to_cpu(req->rpc_vers);
 153                req->prog = be32_to_cpu(req->prog);
 154                req->vers = be32_to_cpu(req->vers);
 155                req->procedure = be32_to_cpu(req->procedure);
 156
 157                server = rpc_server_find(req->prog, req->vers);
 158
 159                if (req->rpc_vers != 2)
 160                        continue;
 161                if (req->type != 0)
 162                        continue;
 163                if (!server) {
 164                        rpc_send_accepted_void_reply(
 165                                endpoint, req->xid,
 166                                RPC_ACCEPTSTAT_PROG_UNAVAIL);
 167                        continue;
 168                }
 169
 170                rc = server->rpc_call(server, req, rc);
 171
 172                switch (rc) {
 173                case 0:
 174                        rpc_send_accepted_void_reply(
 175                                endpoint, req->xid,
 176                                RPC_ACCEPTSTAT_SUCCESS);
 177                        break;
 178                default:
 179                        rpc_send_accepted_void_reply(
 180                                endpoint, req->xid,
 181                                RPC_ACCEPTSTAT_PROG_UNAVAIL);
 182                        break;
 183                }
 184
 185                kfree(buffer);
 186        }
 187
 188        do_exit(0);
 189}
 190
 191static int rpcservers_probe(struct platform_device *pdev)
 192{
 193        struct task_struct *server_thread;
 194
 195        endpoint = msm_rpc_open();
 196        if (IS_ERR(endpoint))
 197                return PTR_ERR(endpoint);
 198
 199        /* we're online -- register any servers installed beforehand */
 200        rpc_servers_active = 1;
 201        rpc_server_register_all();
 202
 203        /* start the kernel thread */
 204        server_thread = kthread_run(rpc_servers_thread, NULL, "krpcserversd");
 205        if (IS_ERR(server_thread))
 206                return PTR_ERR(server_thread);
 207
 208        return 0;
 209}
 210
 211static struct platform_driver rpcservers_driver = {
 212        .probe  = rpcservers_probe,
 213        .driver = {
 214                .name   = "oncrpc_router",
 215                .owner  = THIS_MODULE,
 216        },
 217};
 218
 219static int __init rpc_servers_init(void)
 220{
 221        wake_lock_init(&rpc_servers_wake_lock, WAKE_LOCK_SUSPEND, "rpc_server");
 222        return platform_driver_register(&rpcservers_driver);
 223}
 224
 225module_init(rpc_servers_init);
 226
 227MODULE_DESCRIPTION("MSM RPC Servers");
 228MODULE_AUTHOR("Iliyan Malchev <ibm@android.com>");
 229MODULE_LICENSE("GPL");
 230