1428 lines
32 KiB
C
1428 lines
32 KiB
C
/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
|
|
* Copyright (c) 2009, HTC Corporation. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of Code Aurora Forum nor
|
|
* the names of its contributors may be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* Alternatively, provided that this notice is retained in full, this software
|
|
* may be relicensed by the recipient under the terms of the GNU General Public
|
|
* License version 2 ("GPL") and only version 2, in which case the provisions of
|
|
* the GPL apply INSTEAD OF those given above. If the recipient relicenses the
|
|
* software under the GPL, then the identification text in the MODULE_LICENSE
|
|
* macro must be changed to reflect "GPLv2" instead of "Dual BSD/GPL". Once a
|
|
* recipient changes the license terms to the GPL, subsequent recipients shall
|
|
* not relicense under alternate licensing terms, including the BSD or dual
|
|
* BSD/GPL terms. In addition, the following license statement immediately
|
|
* below and between the words START and END shall also then apply when this
|
|
* software is relicensed under the GPL:
|
|
*
|
|
* START
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* END
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
/*
|
|
* Device access library (DAL) implementation.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/list.h>
|
|
#include <linux/module.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/wait.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/semaphore.h>
|
|
#include <linux/delay.h>
|
|
|
|
#include <mach/dal.h>
|
|
#include <mach/msm_smd.h>
|
|
|
|
#include "smd_private.h"
|
|
#include "smd_debug.h"
|
|
|
|
#define DALRPC_PROTOCOL_VERSION 0x11
|
|
#define DALRPC_SUCCESS 0
|
|
#define DALRPC_MAX_PORTNAME_LEN 64
|
|
#define DALRPC_MAX_ATTACH_PARAM_LEN 64
|
|
#define DALRPC_MAX_SERVICE_NAME_LEN 32
|
|
#define DALRPC_MAX_PARAMS 128
|
|
#define DALRPC_MAX_PARAMS_SIZE (DALRPC_MAX_PARAMS * 4)
|
|
#define DALRPC_MAX_MSG_SIZE (sizeof(struct dalrpc_msg_hdr) + \
|
|
DALRPC_MAX_PARAMS_SIZE)
|
|
#define DALRPC_MSGID_DDI 0x0
|
|
#define DALRPC_MSGID_DDI_REPLY 0x80
|
|
#define DALRPC_MSGID_ATTACH_REPLY 0x81
|
|
#define DALRPC_MSGID_DETACH_REPLY 0x82
|
|
#define DALRPC_MSGID_ASYNCH 0xC0
|
|
#define ROUND_BUFLEN(x) (((x + 3) & ~0x3))
|
|
|
|
#define MAX_RETRY_COUNT 5
|
|
#define RETRY_DELAY 10
|
|
|
|
struct dalrpc_msg_hdr {
|
|
uint32_t len:16;
|
|
uint32_t proto_ver:8;
|
|
uint32_t prio:7;
|
|
uint32_t async:1;
|
|
uint32_t ddi_idx:16;
|
|
uint32_t proto_id:8;
|
|
uint32_t msgid:8;
|
|
void *from;
|
|
void *to;
|
|
};
|
|
|
|
struct dalrpc_msg {
|
|
struct dalrpc_msg_hdr hdr;
|
|
uint32_t param[DALRPC_MAX_PARAMS];
|
|
};
|
|
|
|
struct dalrpc_event_handle {
|
|
struct list_head list;
|
|
|
|
int flag;
|
|
spinlock_t lock;
|
|
};
|
|
|
|
struct dalrpc_cb_handle {
|
|
struct list_head list;
|
|
|
|
void (*fn)(void *, uint32_t, void *, uint32_t);
|
|
void *context;
|
|
};
|
|
|
|
struct daldevice_handle {;
|
|
struct list_head list;
|
|
|
|
void *remote_handle;
|
|
struct completion read_completion;
|
|
struct dalrpc_port *port;
|
|
struct dalrpc_msg msg;
|
|
struct mutex client_lock;
|
|
};
|
|
|
|
struct dalrpc_port {
|
|
struct list_head list;
|
|
|
|
char port[DALRPC_MAX_PORTNAME_LEN+1];
|
|
int refcount;
|
|
|
|
struct workqueue_struct *wq;
|
|
struct work_struct port_work;
|
|
struct mutex write_lock;
|
|
|
|
smd_channel_t *ch;
|
|
|
|
struct dalrpc_msg msg_in;
|
|
struct daldevice_handle *msg_owner;
|
|
unsigned msg_bytes_read;
|
|
|
|
struct list_head event_list;
|
|
struct mutex event_list_lock;
|
|
|
|
struct list_head cb_list;
|
|
struct mutex cb_list_lock;
|
|
};
|
|
|
|
static LIST_HEAD(port_list);
|
|
static LIST_HEAD(client_list);
|
|
static DEFINE_MUTEX(pc_lists_lock);
|
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(event_wq);
|
|
|
|
static int client_exists(void *handle)
|
|
{
|
|
struct daldevice_handle *h;
|
|
|
|
if (!handle)
|
|
return 0;
|
|
|
|
mutex_lock(&pc_lists_lock);
|
|
|
|
list_for_each_entry(h, &client_list, list)
|
|
if (h == handle) {
|
|
mutex_unlock(&pc_lists_lock);
|
|
return 1;
|
|
}
|
|
|
|
mutex_unlock(&pc_lists_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int client_exists_locked(void *handle)
|
|
{
|
|
struct daldevice_handle *h;
|
|
|
|
/* this function must be called with pc_lists_lock acquired */
|
|
|
|
if (!handle)
|
|
return 0;
|
|
|
|
list_for_each_entry(h, &client_list, list)
|
|
if (h == handle)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int port_exists(struct dalrpc_port *p)
|
|
{
|
|
struct dalrpc_port *p_iter;
|
|
|
|
/* this function must be called with pc_lists_lock acquired */
|
|
|
|
if (!p)
|
|
return 0;
|
|
|
|
list_for_each_entry(p_iter, &port_list, list)
|
|
if (p_iter == p)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct dalrpc_port *port_name_exists(char *port)
|
|
{
|
|
struct dalrpc_port *p;
|
|
|
|
/* this function must be called with pc_lists_lock acquired */
|
|
|
|
list_for_each_entry(p, &port_list, list)
|
|
if (!strcmp(p->port, port))
|
|
return p;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void port_close(struct dalrpc_port *p)
|
|
{
|
|
mutex_lock(&pc_lists_lock);
|
|
|
|
p->refcount--;
|
|
if (p->refcount == 0)
|
|
list_del(&p->list);
|
|
|
|
mutex_unlock(&pc_lists_lock);
|
|
|
|
if (p->refcount == 0) {
|
|
destroy_workqueue(p->wq);
|
|
smd_close(p->ch);
|
|
kfree(p);
|
|
}
|
|
}
|
|
|
|
static int event_exists(struct dalrpc_port *p,
|
|
struct dalrpc_event_handle *ev)
|
|
{
|
|
struct dalrpc_event_handle *ev_iter;
|
|
|
|
/* this function must be called with event_list_lock acquired */
|
|
|
|
list_for_each_entry(ev_iter, &p->event_list, list)
|
|
if (ev_iter == ev)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int cb_exists(struct dalrpc_port *p,
|
|
struct dalrpc_cb_handle *cb)
|
|
{
|
|
struct dalrpc_cb_handle *cb_iter;
|
|
|
|
/* this function must be called with the cb_list_lock acquired */
|
|
|
|
list_for_each_entry(cb_iter, &p->cb_list, list)
|
|
if (cb_iter == cb)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_version(struct dalrpc_msg_hdr *msg_hdr)
|
|
{
|
|
static int version_msg = 1;
|
|
|
|
/* disabled because asynch events currently have no version */
|
|
return 0;
|
|
|
|
if (msg_hdr->proto_ver != DALRPC_PROTOCOL_VERSION) {
|
|
if (version_msg) {
|
|
printk(KERN_ERR "dalrpc: incompatible verison\n");
|
|
version_msg = 0;
|
|
}
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void process_asynch(struct dalrpc_port *p)
|
|
{
|
|
struct dalrpc_event_handle *ev;
|
|
struct dalrpc_cb_handle *cb;
|
|
|
|
ev = (struct dalrpc_event_handle *)p->msg_in.param[0];
|
|
cb = (struct dalrpc_cb_handle *)p->msg_in.param[0];
|
|
|
|
mutex_lock(&p->event_list_lock);
|
|
if (event_exists(p, ev)) {
|
|
spin_lock(&ev->lock);
|
|
ev->flag = 1;
|
|
spin_unlock(&ev->lock);
|
|
smp_mb();
|
|
wake_up_all(&event_wq);
|
|
mutex_unlock(&p->event_list_lock);
|
|
return;
|
|
}
|
|
mutex_unlock(&p->event_list_lock);
|
|
|
|
mutex_lock(&p->cb_list_lock);
|
|
if (cb_exists(p, cb)) {
|
|
cb->fn(cb->context, p->msg_in.param[1],
|
|
&p->msg_in.param[3], p->msg_in.param[2]);
|
|
mutex_unlock(&p->cb_list_lock);
|
|
return;
|
|
}
|
|
mutex_unlock(&p->cb_list_lock);
|
|
}
|
|
|
|
static void process_msg(struct dalrpc_port *p)
|
|
{
|
|
switch (p->msg_in.hdr.msgid) {
|
|
|
|
case DALRPC_MSGID_DDI_REPLY:
|
|
case DALRPC_MSGID_ATTACH_REPLY:
|
|
case DALRPC_MSGID_DETACH_REPLY:
|
|
complete(&p->msg_owner->read_completion);
|
|
break;
|
|
|
|
case DALRPC_MSGID_ASYNCH:
|
|
process_asynch(p);
|
|
break;
|
|
|
|
default:
|
|
printk(KERN_ERR "process_msg: bad msgid %#x\n",
|
|
p->msg_in.hdr.msgid);
|
|
}
|
|
}
|
|
|
|
static void flush_msg(struct dalrpc_port *p)
|
|
{
|
|
int bytes_read, len;
|
|
|
|
len = p->msg_in.hdr.len - sizeof(struct dalrpc_msg_hdr);
|
|
while (len > 0) {
|
|
bytes_read = smd_read(p->ch, NULL, len);
|
|
if (bytes_read <= 0)
|
|
break;
|
|
len -= bytes_read;
|
|
}
|
|
p->msg_bytes_read = 0;
|
|
}
|
|
|
|
static int check_header(struct dalrpc_port *p)
|
|
{
|
|
if (check_version(&p->msg_in.hdr) ||
|
|
p->msg_in.hdr.len > DALRPC_MAX_MSG_SIZE ||
|
|
(p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH &&
|
|
!client_exists_locked(p->msg_in.hdr.to))) {
|
|
printk(KERN_ERR "dalrpc_read_msg: bad msg\n");
|
|
flush_msg(p);
|
|
return 1;
|
|
}
|
|
p->msg_owner = (struct daldevice_handle *)p->msg_in.hdr.to;
|
|
|
|
if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
|
|
memcpy(&p->msg_owner->msg.hdr, &p->msg_in.hdr,
|
|
sizeof(p->msg_in.hdr));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int dalrpc_read_msg(struct dalrpc_port *p)
|
|
{
|
|
uint8_t *read_ptr;
|
|
int bytes_read;
|
|
|
|
/* read msg header */
|
|
while (p->msg_bytes_read < sizeof(p->msg_in.hdr)) {
|
|
read_ptr = (uint8_t *)&p->msg_in.hdr + p->msg_bytes_read;
|
|
|
|
bytes_read = smd_read(p->ch, read_ptr,
|
|
sizeof(p->msg_in.hdr) -
|
|
p->msg_bytes_read);
|
|
if (bytes_read <= 0)
|
|
return 0;
|
|
p->msg_bytes_read += bytes_read;
|
|
|
|
if (p->msg_bytes_read == sizeof(p->msg_in.hdr) &&
|
|
check_header(p))
|
|
return 1;
|
|
}
|
|
|
|
/* read remainder of msg */
|
|
if (p->msg_in.hdr.msgid != DALRPC_MSGID_ASYNCH)
|
|
read_ptr = (uint8_t *)&p->msg_owner->msg;
|
|
else
|
|
read_ptr = (uint8_t *)&p->msg_in;
|
|
read_ptr += p->msg_bytes_read;
|
|
|
|
while (p->msg_bytes_read < p->msg_in.hdr.len) {
|
|
bytes_read = smd_read(p->ch, read_ptr,
|
|
p->msg_in.hdr.len - p->msg_bytes_read);
|
|
if (bytes_read <= 0)
|
|
return 0;
|
|
p->msg_bytes_read += bytes_read;
|
|
read_ptr += bytes_read;
|
|
}
|
|
|
|
process_msg(p);
|
|
p->msg_bytes_read = 0;
|
|
p->msg_owner = NULL;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static void dalrpc_work(struct work_struct *work)
|
|
{
|
|
struct dalrpc_port *p = container_of(work,
|
|
struct dalrpc_port,
|
|
port_work);
|
|
|
|
/* must lock port/client lists to ensure port doesn't disappear
|
|
under an asynch event */
|
|
mutex_lock(&pc_lists_lock);
|
|
if (port_exists(p))
|
|
while (dalrpc_read_msg(p))
|
|
;
|
|
mutex_unlock(&pc_lists_lock);
|
|
}
|
|
|
|
static void dalrpc_smd_cb(void *priv, unsigned smd_flags)
|
|
{
|
|
struct dalrpc_port *p = priv;
|
|
|
|
if (smd_flags != SMD_EVENT_DATA)
|
|
return;
|
|
|
|
queue_work(p->wq, &p->port_work);
|
|
}
|
|
|
|
static struct dalrpc_port *dalrpc_port_open(char *port, int cpu)
|
|
{
|
|
struct dalrpc_port *p;
|
|
char wq_name[32];
|
|
|
|
p = port_name_exists(port);
|
|
if (p) {
|
|
p->refcount++;
|
|
return p;
|
|
}
|
|
|
|
p = kzalloc(sizeof(struct dalrpc_port), GFP_KERNEL);
|
|
if (!p)
|
|
return NULL;
|
|
|
|
strncpy(p->port, port, sizeof(p->port) - 1);
|
|
p->refcount = 1;
|
|
|
|
snprintf(wq_name, sizeof(wq_name), "dalrpc_rcv_%s", port);
|
|
p->wq = create_singlethread_workqueue(wq_name);
|
|
if (!p->wq) {
|
|
printk(KERN_ERR "dalrpc_init: unable to create workqueue\n");
|
|
goto no_wq;
|
|
}
|
|
INIT_WORK(&p->port_work, dalrpc_work);
|
|
|
|
mutex_init(&p->write_lock);
|
|
mutex_init(&p->event_list_lock);
|
|
mutex_init(&p->cb_list_lock);
|
|
|
|
INIT_LIST_HEAD(&p->event_list);
|
|
INIT_LIST_HEAD(&p->cb_list);
|
|
|
|
p->msg_owner = NULL;
|
|
p->msg_bytes_read = 0;
|
|
|
|
#if 1 //HK test
|
|
if (smd_open(port, &p->ch, p, dalrpc_smd_cb)) {
|
|
#else
|
|
if (smd_named_open_on_edge(port, cpu, &p->ch, p,
|
|
dalrpc_smd_cb)) {
|
|
#endif
|
|
printk(KERN_ERR "dalrpc_port_init() failed to open port\n");
|
|
goto no_smd;
|
|
}
|
|
|
|
list_add(&p->list, &port_list);
|
|
|
|
return p;
|
|
|
|
no_smd:
|
|
destroy_workqueue(p->wq);
|
|
no_wq:
|
|
kfree(p);
|
|
return NULL;
|
|
}
|
|
|
|
static void dalrpc_sendwait(struct daldevice_handle *h)
|
|
{
|
|
u8 *buf = (u8 *)&h->msg;
|
|
int len = h->msg.hdr.len;
|
|
int written;
|
|
|
|
mutex_lock(&h->port->write_lock);
|
|
do {
|
|
if ((h->port->ch->recv->state != SMD_SS_OPENED) ||
|
|
(h->port->ch->send->state != SMD_SS_OPENED)) {
|
|
printk(KERN_ERR "%s: smd channel %s not ready,"
|
|
" wait 100ms.\n", __func__, h->port->ch->name);
|
|
mdelay(100);
|
|
continue;
|
|
}
|
|
written = smd_write(h->port->ch, buf + (h->msg.hdr.len - len),
|
|
len);
|
|
if (written < 0)
|
|
break;
|
|
len -= written;
|
|
} while (len);
|
|
|
|
/* Original codes put wait_for_completion outside of mutex
|
|
* that may cause the latter session overwrites data from
|
|
* previous session before aDSP really gets it. Thus, move
|
|
* wait_for_completion inside the mutex to prevent data
|
|
* corruption. */
|
|
wait_for_completion(&h->read_completion);
|
|
|
|
mutex_unlock(&h->port->write_lock);
|
|
|
|
}
|
|
|
|
int daldevice_attach(uint32_t device_id, char *port, int cpu,
|
|
void **handle_ptr)
|
|
{
|
|
struct daldevice_handle *h;
|
|
char dyn_port[DALRPC_MAX_PORTNAME_LEN + 1] = "DAL00";
|
|
int ret;
|
|
int tries = 0;
|
|
|
|
if (!port)
|
|
port = dyn_port;
|
|
|
|
if (strlen(port) > DALRPC_MAX_PORTNAME_LEN)
|
|
return -EINVAL;
|
|
|
|
h = kzalloc(sizeof(struct daldevice_handle), GFP_KERNEL);
|
|
if (!h) {
|
|
*handle_ptr = NULL;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
init_completion(&h->read_completion);
|
|
mutex_init(&h->client_lock);
|
|
|
|
mutex_lock(&pc_lists_lock);
|
|
list_add(&h->list, &client_list);
|
|
mutex_unlock(&pc_lists_lock);
|
|
|
|
/* 3 attempts, enough for one each on the user specified port, the
|
|
* dynamic discovery port, and the port recommended by the dynamic
|
|
* discovery port */
|
|
while (tries < 3) {
|
|
tries++;
|
|
|
|
mutex_lock(&pc_lists_lock);
|
|
h->port = dalrpc_port_open(port, cpu);
|
|
if (!h->port) {
|
|
list_del(&h->list);
|
|
mutex_unlock(&pc_lists_lock);
|
|
printk(KERN_ERR "daldevice_attach: could not "
|
|
"open port\n");
|
|
kfree(h);
|
|
*handle_ptr = NULL;
|
|
return -EIO;
|
|
}
|
|
mutex_unlock(&pc_lists_lock);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
|
|
DALRPC_MAX_ATTACH_PARAM_LEN +
|
|
DALRPC_MAX_SERVICE_NAME_LEN;
|
|
h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
|
|
h->msg.hdr.ddi_idx = 0;
|
|
h->msg.hdr.msgid = 0x1;
|
|
h->msg.hdr.prio = 0;
|
|
h->msg.hdr.async = 0;
|
|
h->msg.hdr.from = h;
|
|
h->msg.hdr.to = 0;
|
|
h->msg.param[0] = device_id;
|
|
|
|
memset(&h->msg.param[1], 0,
|
|
DALRPC_MAX_ATTACH_PARAM_LEN +
|
|
DALRPC_MAX_SERVICE_NAME_LEN);
|
|
|
|
dalrpc_sendwait(h);
|
|
ret = h->msg.param[0];
|
|
|
|
if (ret == DALRPC_SUCCESS) {
|
|
h->remote_handle = h->msg.hdr.from;
|
|
*handle_ptr = h;
|
|
break;
|
|
} else if (strnlen((char *)&h->msg.param[1],
|
|
DALRPC_MAX_PORTNAME_LEN)) {
|
|
/* another port was recommended in the response. */
|
|
strncpy(dyn_port, (char *)&h->msg.param[1],
|
|
DALRPC_MAX_PORTNAME_LEN);
|
|
dyn_port[DALRPC_MAX_PORTNAME_LEN] = 0;
|
|
port = dyn_port;
|
|
} else if (port == dyn_port) {
|
|
/* the dynamic discovery port (or port that
|
|
* was recommended by it) did not recognize
|
|
* the device id, give up */
|
|
daldevice_detach(h);
|
|
break;
|
|
} else
|
|
/* the user specified port did not work, try
|
|
* the dynamic discovery port */
|
|
port = dyn_port;
|
|
|
|
port_close(h->port);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(daldevice_attach);
|
|
|
|
static void dalrpc_ddi_prologue(uint32_t ddi_idx, struct daldevice_handle *h)
|
|
{
|
|
h->msg.hdr.proto_ver = DALRPC_PROTOCOL_VERSION;
|
|
h->msg.hdr.prio = 0;
|
|
h->msg.hdr.async = 0;
|
|
h->msg.hdr.msgid = DALRPC_MSGID_DDI;
|
|
h->msg.hdr.from = h;
|
|
h->msg.hdr.to = h->remote_handle;
|
|
h->msg.hdr.ddi_idx = ddi_idx;
|
|
}
|
|
|
|
int daldevice_detach(void *handle)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
dalrpc_ddi_prologue(0, h);
|
|
|
|
if (!h->remote_handle)
|
|
goto norpc;
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
|
|
h->msg.hdr.msgid = 0x2;
|
|
h->msg.param[0] = 0;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
norpc:
|
|
mutex_lock(&pc_lists_lock);
|
|
list_del(&h->list);
|
|
mutex_unlock(&pc_lists_lock);
|
|
|
|
port_close(h->port);
|
|
|
|
kfree(h);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(daldevice_detach);
|
|
|
|
uint32_t dalrpc_fcn_0(uint32_t ddi_idx, void *handle, uint32_t s1)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
uint32_t retry_count = 0;
|
|
|
|
if (!client_exists(h))
|
|
{
|
|
printk(KERN_ERR "client_exists FALSE\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
mutex_lock(&h->client_lock);
|
|
again:
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
|
|
h->msg.hdr.proto_id = 0;
|
|
h->msg.param[0] = s1;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
ret = h->msg.param[0];
|
|
|
|
if (ret && retry_count++ < MAX_RETRY_COUNT) {
|
|
printk(KERN_INFO "*********** %s: %d retry %d times, ret %d\n",
|
|
__func__, ddi_idx, retry_count, ret);
|
|
mdelay(RETRY_DELAY);
|
|
goto again;
|
|
}
|
|
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_0);
|
|
|
|
uint32_t dalrpc_fcn_1(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
uint32_t s2)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
uint32_t retry_count = 0;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
again:
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
|
|
h->msg.hdr.proto_id = 1;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = s2;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
ret = h->msg.param[0];
|
|
|
|
if (ret && retry_count++ < MAX_RETRY_COUNT) {
|
|
printk(KERN_INFO "*********** %s: %d retry %d times, ret %d\n",
|
|
__func__, ddi_idx, retry_count, ret);
|
|
mdelay(RETRY_DELAY);
|
|
goto again;
|
|
}
|
|
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_1);
|
|
|
|
uint32_t dalrpc_fcn_2(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
uint32_t *p_s2)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
|
|
h->msg.hdr.proto_id = 2;
|
|
h->msg.param[0] = s1;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS)
|
|
*p_s2 = h->msg.param[1];
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_2);
|
|
|
|
uint32_t dalrpc_fcn_3(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
uint32_t s2, uint32_t s3)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12;
|
|
h->msg.hdr.proto_id = 3;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = s2;
|
|
h->msg.param[2] = s3;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_3);
|
|
|
|
uint32_t dalrpc_fcn_4(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
uint32_t s2, uint32_t *p_s3)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
|
|
h->msg.hdr.proto_id = 4;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = s2;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS)
|
|
*p_s3 = h->msg.param[1];
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_4);
|
|
|
|
uint32_t dalrpc_fcn_5(uint32_t ddi_idx, void *handle, const void *ibuf,
|
|
uint32_t ilen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
uint32_t retry_count = 0;
|
|
|
|
if ((ilen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
again:
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4 +
|
|
ROUND_BUFLEN(ilen);
|
|
h->msg.hdr.proto_id = 5;
|
|
h->msg.param[0] = ilen;
|
|
memcpy(&h->msg.param[1], ibuf, ilen);
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
ret = h->msg.param[0];
|
|
|
|
if (ret && retry_count++ < MAX_RETRY_COUNT) {
|
|
printk(KERN_INFO "*********** %s: %d retry %d times, ret %d\n",
|
|
__func__, ddi_idx, retry_count, ret);
|
|
mdelay(RETRY_DELAY);
|
|
goto again;
|
|
}
|
|
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_5);
|
|
|
|
uint32_t dalrpc_fcn_6(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
const void *ibuf, uint32_t ilen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
uint32_t retry_count = 0;
|
|
|
|
if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
again:
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
|
|
ROUND_BUFLEN(ilen);
|
|
h->msg.hdr.proto_id = 6;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = ilen;
|
|
memcpy(&h->msg.param[2], ibuf, ilen);
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
ret = h->msg.param[0];
|
|
|
|
if (ret && retry_count++ < MAX_RETRY_COUNT) {
|
|
printk(KERN_INFO "*********** %s: %d retry %d times, ret %d\n",
|
|
__func__, ddi_idx, retry_count, ret);
|
|
mdelay(RETRY_DELAY);
|
|
goto again;
|
|
}
|
|
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_6);
|
|
|
|
uint32_t dalrpc_fcn_7(uint32_t ddi_idx, void *handle, const void *ibuf,
|
|
uint32_t ilen, void *obuf, uint32_t olen,
|
|
uint32_t *oalen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
int param_idx;
|
|
|
|
if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
|
|
(olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
|
|
ROUND_BUFLEN(ilen);
|
|
h->msg.hdr.proto_id = 7;
|
|
h->msg.param[0] = ilen;
|
|
memcpy(&h->msg.param[1], ibuf, ilen);
|
|
param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
|
|
h->msg.param[param_idx] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
*oalen = h->msg.param[1];
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_7);
|
|
|
|
uint32_t dalrpc_fcn_8(uint32_t ddi_idx, void *handle, const void *ibuf,
|
|
uint32_t ilen, void *obuf, uint32_t olen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
int param_idx;
|
|
|
|
if ((ilen + 8) > DALRPC_MAX_PARAMS_SIZE ||
|
|
(olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8 +
|
|
ROUND_BUFLEN(ilen);
|
|
h->msg.hdr.proto_id = 8;
|
|
h->msg.param[0] = ilen;
|
|
memcpy(&h->msg.param[1], ibuf, ilen);
|
|
param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
|
|
h->msg.param[param_idx] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_8);
|
|
|
|
uint32_t dalrpc_fcn_9(uint32_t ddi_idx, void *handle, void *obuf,
|
|
uint32_t olen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
|
|
if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 4;
|
|
h->msg.hdr.proto_id = 9;
|
|
h->msg.param[0] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_9);
|
|
|
|
uint32_t dalrpc_fcn_10(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
const void *ibuf, uint32_t ilen, void *obuf,
|
|
uint32_t olen, uint32_t *oalen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
int param_idx;
|
|
|
|
if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
|
|
(olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
|
|
ROUND_BUFLEN(ilen);
|
|
h->msg.hdr.proto_id = 10;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = ilen;
|
|
memcpy(&h->msg.param[2], ibuf, ilen);
|
|
param_idx = (ROUND_BUFLEN(ilen) / 4) + 2;
|
|
h->msg.param[param_idx] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
*oalen = h->msg.param[1];
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_10);
|
|
|
|
uint32_t dalrpc_fcn_11(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
void *obuf, uint32_t olen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
|
|
if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
|
|
h->msg.hdr.proto_id = 11;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_11);
|
|
|
|
uint32_t dalrpc_fcn_12(uint32_t ddi_idx, void *handle, uint32_t s1,
|
|
void *obuf, uint32_t olen, uint32_t *oalen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
|
|
if ((olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 8;
|
|
h->msg.hdr.proto_id = 12;
|
|
h->msg.param[0] = s1;
|
|
h->msg.param[1] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
*oalen = h->msg.param[1];
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_12);
|
|
|
|
uint32_t dalrpc_fcn_13(uint32_t ddi_idx, void *handle, const void *ibuf,
|
|
uint32_t ilen, const void *ibuf2, uint32_t ilen2,
|
|
void *obuf, uint32_t olen)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
int param_idx;
|
|
|
|
if ((ilen + ilen2 + 12) > DALRPC_MAX_PARAMS_SIZE ||
|
|
(olen + 4) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
|
|
ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
|
|
h->msg.hdr.proto_id = 13;
|
|
h->msg.param[0] = ilen;
|
|
memcpy(&h->msg.param[1], ibuf, ilen);
|
|
param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
|
|
h->msg.param[param_idx++] = ilen2;
|
|
memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
|
|
param_idx += (ROUND_BUFLEN(ilen2) / 4);
|
|
h->msg.param[param_idx] = olen;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_13);
|
|
|
|
uint32_t dalrpc_fcn_14(uint32_t ddi_idx, void *handle, const void *ibuf,
|
|
uint32_t ilen, void *obuf, uint32_t olen,
|
|
void *obuf2, uint32_t olen2, uint32_t *oalen2)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
int param_idx;
|
|
|
|
if ((ilen + 12) > DALRPC_MAX_PARAMS_SIZE ||
|
|
(olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 12 +
|
|
ROUND_BUFLEN(ilen);
|
|
h->msg.hdr.proto_id = 14;
|
|
h->msg.param[0] = ilen;
|
|
memcpy(&h->msg.param[1], ibuf, ilen);
|
|
param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
|
|
h->msg.param[param_idx++] = olen;
|
|
h->msg.param[param_idx] = olen2;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
|
|
if (h->msg.param[param_idx] > olen2) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
memcpy(obuf2, &h->msg.param[param_idx + 1],
|
|
h->msg.param[param_idx]);
|
|
*oalen2 = h->msg.param[param_idx];
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_14);
|
|
|
|
uint32_t dalrpc_fcn_15(uint32_t ddi_idx, void *handle, const void *ibuf,
|
|
uint32_t ilen, const void *ibuf2, uint32_t ilen2,
|
|
void *obuf, uint32_t olen, uint32_t *oalen,
|
|
void *obuf2, uint32_t olen2)
|
|
{
|
|
struct daldevice_handle *h = handle;
|
|
uint32_t ret;
|
|
int param_idx;
|
|
|
|
if ((ilen + ilen2 + 16) > DALRPC_MAX_PARAMS_SIZE ||
|
|
(olen + olen2 + 8) > DALRPC_MAX_PARAMS_SIZE)
|
|
return -EINVAL;
|
|
|
|
if (!client_exists(h))
|
|
return -EINVAL;
|
|
|
|
mutex_lock(&h->client_lock);
|
|
dalrpc_ddi_prologue(ddi_idx, h);
|
|
|
|
h->msg.hdr.len = sizeof(struct dalrpc_msg_hdr) + 16 +
|
|
ROUND_BUFLEN(ilen) + ROUND_BUFLEN(ilen2);
|
|
h->msg.hdr.proto_id = 15;
|
|
h->msg.param[0] = ilen;
|
|
memcpy(&h->msg.param[1], ibuf, ilen);
|
|
param_idx = (ROUND_BUFLEN(ilen) / 4) + 1;
|
|
h->msg.param[param_idx++] = ilen2;
|
|
memcpy(&h->msg.param[param_idx], ibuf2, ilen2);
|
|
param_idx += (ROUND_BUFLEN(ilen2) / 4);
|
|
h->msg.param[param_idx++] = olen;
|
|
h->msg.param[param_idx] = olen2;
|
|
|
|
dalrpc_sendwait(h);
|
|
|
|
if (h->msg.param[0] == DALRPC_SUCCESS) {
|
|
if (h->msg.param[1] > olen) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
param_idx = (ROUND_BUFLEN(h->msg.param[1]) / 4) + 2;
|
|
if (h->msg.param[param_idx] > olen2) {
|
|
mutex_unlock(&h->client_lock);
|
|
return -EIO;
|
|
}
|
|
memcpy(obuf, &h->msg.param[2], h->msg.param[1]);
|
|
memcpy(obuf2, &h->msg.param[param_idx + 1],
|
|
h->msg.param[param_idx]);
|
|
*oalen = h->msg.param[1];
|
|
}
|
|
|
|
ret = h->msg.param[0];
|
|
mutex_unlock(&h->client_lock);
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_fcn_15);
|
|
|
|
void *dalrpc_alloc_event(void *handle)
|
|
{
|
|
struct daldevice_handle *h;
|
|
struct dalrpc_event_handle *ev;
|
|
|
|
h = (struct daldevice_handle *)handle;
|
|
|
|
if (!client_exists(h))
|
|
return NULL;
|
|
|
|
ev = kmalloc(sizeof(struct dalrpc_event_handle), GFP_KERNEL);
|
|
if (!ev)
|
|
return NULL;
|
|
|
|
ev->flag = 0;
|
|
spin_lock_init(&ev->lock);
|
|
|
|
mutex_lock(&h->port->event_list_lock);
|
|
list_add(&ev->list, &h->port->event_list);
|
|
mutex_unlock(&h->port->event_list_lock);
|
|
|
|
return ev;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_alloc_event);
|
|
|
|
void *dalrpc_alloc_cb(void *handle,
|
|
void (*fn)(void *, uint32_t, void *, uint32_t),
|
|
void *context)
|
|
{
|
|
struct daldevice_handle *h;
|
|
struct dalrpc_cb_handle *cb;
|
|
|
|
h = (struct daldevice_handle *)handle;
|
|
|
|
if (!client_exists(h))
|
|
return NULL;
|
|
|
|
cb = kmalloc(sizeof(struct dalrpc_cb_handle), GFP_KERNEL);
|
|
if (!cb)
|
|
return NULL;
|
|
|
|
cb->fn = fn;
|
|
cb->context = context;
|
|
|
|
mutex_lock(&h->port->cb_list_lock);
|
|
list_add(&cb->list, &h->port->cb_list);
|
|
mutex_unlock(&h->port->cb_list_lock);
|
|
|
|
return cb;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_alloc_cb);
|
|
|
|
void dalrpc_dealloc_event(void *handle,
|
|
void *ev_h)
|
|
{
|
|
struct daldevice_handle *h;
|
|
struct dalrpc_event_handle *ev;
|
|
|
|
h = (struct daldevice_handle *)handle;
|
|
ev = (struct dalrpc_event_handle *)ev_h;
|
|
|
|
mutex_lock(&h->port->event_list_lock);
|
|
list_del(&ev->list);
|
|
mutex_unlock(&h->port->event_list_lock);
|
|
kfree(ev);
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_dealloc_event);
|
|
|
|
void dalrpc_dealloc_cb(void *handle,
|
|
void *cb_h)
|
|
{
|
|
struct daldevice_handle *h;
|
|
struct dalrpc_cb_handle *cb;
|
|
|
|
h = (struct daldevice_handle *)handle;
|
|
cb = (struct dalrpc_cb_handle *)cb_h;
|
|
|
|
mutex_lock(&h->port->cb_list_lock);
|
|
list_del(&cb->list);
|
|
mutex_unlock(&h->port->cb_list_lock);
|
|
kfree(cb);
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_dealloc_cb);
|
|
|
|
static int event_occurred(int num_events, struct dalrpc_event_handle **events,
|
|
int *occurred)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num_events; i++) {
|
|
spin_lock(&events[i]->lock);
|
|
if (events[i]->flag) {
|
|
events[i]->flag = 0;
|
|
spin_unlock(&events[i]->lock);
|
|
*occurred = i;
|
|
return 1;
|
|
}
|
|
spin_unlock(&events[i]->lock);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dalrpc_event_wait_multiple(int num, void **ev_h, int timeout)
|
|
{
|
|
struct dalrpc_event_handle **events;
|
|
int ret, occurred;
|
|
|
|
events = (struct dalrpc_event_handle **)ev_h;
|
|
|
|
if (timeout == DALRPC_TIMEOUT_INFINITE) {
|
|
wait_event(event_wq,
|
|
event_occurred(num, events, &occurred));
|
|
return occurred;
|
|
}
|
|
|
|
ret = wait_event_timeout(event_wq,
|
|
event_occurred(num, events, &occurred),
|
|
timeout);
|
|
if (ret > 0)
|
|
return occurred;
|
|
else
|
|
return -ETIMEDOUT;
|
|
}
|
|
EXPORT_SYMBOL(dalrpc_event_wait_multiple);
|