mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-10-31 18:09:19 +00:00
270b4100b5
Convert CamelCase style to more Linux appropriate style of coding. Change-Id: I219cfba44cf27441905800cd07afac50666c9832 Acked-by: Vladik Goytin <c_vgoyti@qti.qualcomm.com> Signed-off-by: Rohit Vaswani <rvaswani@codeaurora.org>
256 lines
6.4 KiB
C
256 lines
6.4 KiB
C
/*
|
|
All files except if stated otherwise in the begining of the file
|
|
are under the ISC license:
|
|
----------------------------------------------------------------------
|
|
|
|
Copyright (c) 2010-2012 Design Art Networks Ltd.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/ioctl.h>
|
|
|
|
#include "danipc_k.h"
|
|
#include "ipc_api.h"
|
|
#include "danipc_lowlevel.h"
|
|
|
|
|
|
struct agent_data {
|
|
struct task_struct *task;
|
|
pid_t pid;
|
|
};
|
|
struct agent_data agent_data[MAX_LOCAL_AGENT];
|
|
|
|
static int
|
|
is_process_alive(const struct agent_data *agent_data_p)
|
|
{
|
|
int rc = 0;
|
|
struct task_struct *task = find_task_by_vpid(agent_data_p->pid);
|
|
|
|
if (task) {
|
|
/* Paranoid check: task_struct exists, now verify it belongs
|
|
* to the correct process.
|
|
*/
|
|
if (agent_data_p->task == task &&
|
|
agent_data_p->pid == task->pid)
|
|
rc = 1;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
ipc_gc(void)
|
|
{
|
|
unsigned lid;
|
|
|
|
for (lid = 0; lid < MAX_LOCAL_AGENT; lid++) {
|
|
struct agent_data *agent_data_p = &agent_data[lid];
|
|
|
|
if (agent_data_p->task && !is_process_alive(agent_data_p)) {
|
|
agent_data_p->task = NULL;
|
|
agent_data_p->pid = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
danipc_strncmp(const char *cs, const char *ct, size_t cs_size, size_t ct_size)
|
|
{
|
|
return ((strnlen(cs, cs_size) == strnlen(ct, ct_size)) &&
|
|
(strcmp(cs, ct) == 0));
|
|
}
|
|
|
|
/* Second registration is allowed only for the same process. */
|
|
static int
|
|
second_registration(struct danipc_reg *danipc_reg_p, const int aid,
|
|
const unsigned lid)
|
|
{
|
|
return (danipc_strncmp(agent_table[aid].name, danipc_reg_p->name,
|
|
MAX_AGENT_NAME_LEN, MAX_AGENT_NAME) &&
|
|
agent_data[lid].task == current) ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
register_agent(struct net_device *dev, struct danipc_reg *danipc_reg_p)
|
|
{
|
|
struct danipc_reg danipc_reg;
|
|
unsigned r_lid;
|
|
unsigned agent_id = INVALID_ID;
|
|
int rc = 0;
|
|
|
|
ipc_gc();
|
|
|
|
if (copy_from_user(&danipc_reg, danipc_reg_p, sizeof(danipc_reg)))
|
|
return -EFAULT;
|
|
|
|
r_lid = danipc_reg.requested_lid;
|
|
|
|
if (r_lid != INVALID_ID) {
|
|
const unsigned r_aid = __IPC_AGENT_ID(LOCAL_IPC_ID, r_lid);
|
|
|
|
/* Requested ID is not used, so assign it */
|
|
if (!*agent_table[r_aid].name ||
|
|
second_registration(&danipc_reg, r_aid, r_lid) ||
|
|
(danipc_strncmp(danipc_reg.name,
|
|
agent_table[r_aid].name,
|
|
MAX_AGENT_NAME, MAX_AGENT_NAME_LEN) &&
|
|
agent_data[r_lid].task == NULL)) {
|
|
if (put_user(r_lid, &danipc_reg_p->assigned_lid))
|
|
return -EFAULT;
|
|
agent_id = r_aid;
|
|
}
|
|
}
|
|
|
|
if (agent_id == INVALID_ID) {
|
|
unsigned lid;
|
|
/* Scan for the ID already assigned */
|
|
for (lid = 0; lid < MAX_LOCAL_AGENT; lid++) {
|
|
const unsigned aid = __IPC_AGENT_ID(LOCAL_IPC_ID, lid);
|
|
if (danipc_strncmp(danipc_reg.name,
|
|
agent_table[aid].name,
|
|
MAX_AGENT_NAME, MAX_AGENT_NAME_LEN)
|
|
&& agent_data[lid].task == NULL) {
|
|
if (put_user(lid, &danipc_reg_p->assigned_lid))
|
|
return -EFAULT;
|
|
agent_id = aid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (agent_id == INVALID_ID) {
|
|
unsigned lid;
|
|
/* Scan for the 1st free ID */
|
|
for (lid = 0; lid < MAX_LOCAL_AGENT; lid++) {
|
|
const unsigned aid = __IPC_AGENT_ID(LOCAL_IPC_ID, lid);
|
|
if (!*agent_table[aid].name ||
|
|
second_registration(&danipc_reg, aid, lid)) {
|
|
if (put_user(lid, &danipc_reg_p->assigned_lid))
|
|
return -EFAULT;
|
|
agent_id = aid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (agent_id != INVALID_ID) {
|
|
const unsigned an_siz = sizeof(agent_table[agent_id].name);
|
|
const uint16_t cookie = cpu_to_be16(AGENTID_TO_COOKIE(agent_id,
|
|
danipc_reg.prio));
|
|
strlcpy(agent_table[agent_id].name, danipc_reg.name,
|
|
an_siz);
|
|
agent_table[agent_id].name[an_siz-1] = 0;
|
|
if (put_user(cookie, &danipc_reg_p->cookie))
|
|
rc = -EFAULT;
|
|
agent_data[ipc_lid(agent_id)].task = current;
|
|
agent_data[ipc_lid(agent_id)].pid = current->pid;
|
|
netdev_dbg(dev,
|
|
"%s: agent_id=0x%x assigned_lid=0x%x agent_table[]=\"%s\"\n",
|
|
__func__, agent_id, danipc_reg.assigned_lid,
|
|
agent_table[agent_id].name);
|
|
} else
|
|
rc = -ENOBUFS;
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
get_name_by_addr(struct net_device *dev, struct danipc_name *danipc_name_p)
|
|
{
|
|
int rc = -ENODATA;
|
|
danipc_addr_t addr;
|
|
|
|
if (get_user(addr, &danipc_name_p->addr))
|
|
return -EFAULT;
|
|
|
|
if (*agent_table[addr].name) {
|
|
if (copy_to_user(danipc_name_p->name,
|
|
agent_table[danipc_name_p->addr].name,
|
|
sizeof(danipc_name_p->name)))
|
|
rc = -EFAULT;
|
|
else
|
|
rc = 0;
|
|
netdev_dbg(dev, "%s(): addr=0x%x -> name=%s\n", __func__,
|
|
addr, agent_table[danipc_name_p->addr].name);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int
|
|
get_addr_by_name(struct net_device *dev, struct danipc_name *danipc_name_p)
|
|
{
|
|
char name[MAX_AGENT_NAME];
|
|
int rc = -ENODATA;
|
|
unsigned aid;
|
|
|
|
if (copy_from_user(name, danipc_name_p->name, sizeof(name)))
|
|
return -EFAULT;
|
|
|
|
for (aid = 0; aid < MAX_AGENTS; aid++) {
|
|
if (danipc_strncmp(name, agent_table[aid].name,
|
|
MAX_AGENT_NAME, MAX_AGENT_NAME_LEN)) {
|
|
const unsigned cpuid = aid / MAX_LOCAL_AGENT;
|
|
const unsigned lid = aid % MAX_LOCAL_AGENT;
|
|
if (put_user(__IPC_AGENT_ID(cpuid, lid),
|
|
&danipc_name_p->addr))
|
|
rc = -EFAULT;
|
|
else
|
|
rc = 0;
|
|
netdev_dbg(dev, "%s: name=%s -> addr=0x%x\n", __func__,
|
|
agent_table[aid].name, aid);
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
|
|
int danipc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
|
{
|
|
int rc = -EINVAL;
|
|
|
|
if (dev && ifr && ifr->ifr_data) {
|
|
struct danipc_priv *priv = netdev_priv(dev);
|
|
|
|
mutex_lock(&priv->lock);
|
|
switch (cmd) {
|
|
case DANIPC_IOCS_REGISTER:
|
|
rc = register_agent(dev,
|
|
(struct danipc_reg *)ifr->ifr_data);
|
|
break;
|
|
case DANIPC_IOCG_ADDR2NAME:
|
|
rc = get_name_by_addr(dev,
|
|
(struct danipc_name *)ifr->ifr_data);
|
|
break;
|
|
case DANIPC_IOCG_NAME2ADDR:
|
|
rc = get_addr_by_name(dev,
|
|
(struct danipc_name *)ifr->ifr_data);
|
|
break;
|
|
}
|
|
mutex_unlock(&priv->lock);
|
|
}
|
|
return rc;
|
|
}
|