android_kernel_modules_leno.../intel_media/display/pnw/drv/dispmgrnl.c

247 lines
6.4 KiB
C

/*
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Hitesh K. Patel <hitesh.k.patel@intel.com>
*
*/
#include <linux/version.h>
#include <linux/fs.h>
#include <net/genetlink.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include "dispmgrnl.h"
#include "psb_dpst_func.h"
#include "psb_powermgmt.h"
#define NETLINK_DISPMGR 20
static unsigned int g_pid;
struct sock *nl_sk;
static void execute_recv_command(struct dispmgr_command_hdr *cmd_hdr)
{
switch (cmd_hdr->module) {
case DISPMGR_MOD_NETLINK:
{
switch (cmd_hdr->cmd) {
case DISPMGR_TEST:
{
struct dispmgr_command_hdr send_cmd_hdr;
unsigned long data = 0xdeadbeef;
if (cmd_hdr->data_size) {
unsigned long value =
*((unsigned long *)
cmd_hdr->data);
printk
("kdispmgr: received DISPMGR_"
"TEST cmd data = 0x%lx.\n",
value);
} else {
printk
("kdispmgr: received DISPMGR_"
"TEST cmd NO data.\n");
}
send_cmd_hdr.data_size = sizeof(data);
send_cmd_hdr.data = &data;
send_cmd_hdr.module =
DISPMGR_MOD_NETLINK;
send_cmd_hdr.cmd = DISPMGR_TEST;
dispmgr_nl_send_msg(&send_cmd_hdr);
}
break;
case DISPMGR_TEST_TEXT:
{
struct dispmgr_command_hdr send_cmd_hdr;
char *data = "can you hear me?";
if (cmd_hdr->data_size) {
printk
("kdispmgr: received DISPMGR_"
"TEST_TEXT cmd text = 0x%s.\n",
(char *)cmd_hdr->data);
} else {
printk
("kdispmgr: received DISPMGR_"
"TEST_TEXT cmd NO text.\n");
}
send_cmd_hdr.module =
DISPMGR_MOD_NETLINK;
send_cmd_hdr.cmd = DISPMGR_TEST_TEXT;
send_cmd_hdr.data_size =
strlen(data) + 1;
send_cmd_hdr.data = (void *)data;
dispmgr_nl_send_msg(&send_cmd_hdr);
}
break;
default:
{
printk
("kdispmgr: received unknown "
"command = %d.\n",
cmd_hdr->cmd);
};
}; /* switch */
}
break;
case DISPMGR_MOD_DPST:
{
dpst_execute_recv_command(cmd_hdr);
}
break;
default:
{
printk
("kdispmgr: received unknown "
"module = %d.\n", cmd_hdr->module);
};
} /* switch */
}
/* Send Message to user mode */
void dispmgr_nl_send_msg(struct dispmgr_command_hdr *cmd_hdr)
{
struct nlmsghdr *nlh;
struct sk_buff *skb_out;
unsigned int msg_size = 0;
unsigned int data_size = 0;
unsigned int hdr_size = 0;
int ret = 0;
/* if no user mode process active */
if (!g_pid)
return;
hdr_size = sizeof(struct dispmgr_command_hdr);
data_size = hdr_size + cmd_hdr->data_size;
msg_size = data_size + sizeof(struct nlmsghdr);
skb_out = nlmsg_new(msg_size, 0);
if (!skb_out) {
printk
("kdispmgr: Failed to allocated skb\n");
return;
}
nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0);
NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
memcpy(nlmsg_data(nlh), cmd_hdr, hdr_size);
if (cmd_hdr->data_size) {
memcpy(nlmsg_data(nlh) + hdr_size, cmd_hdr->data,
cmd_hdr->data_size);
}
ret = netlink_unicast(nl_sk, skb_out, g_pid, MSG_DONTWAIT);
}
/* Receive Message from Kernel */
static void nl_recv_msg(struct sk_buff *skb)
{
struct nlmsghdr *nlh = NULL;
struct dispmgr_command_hdr cmd_hdr = {0, };
unsigned int hdr_size = sizeof(struct dispmgr_command_hdr);
if (skb == NULL) {
DRM_ERROR("kdispmgr: received null command.\n");
return;
}
nlh = (struct nlmsghdr *)skb->data;
g_pid = nlh->nlmsg_pid;
pr_debug("kdispmgr: received message from user mode\n");
memcpy((void *)(&cmd_hdr), NLMSG_DATA(nlh), hdr_size);
if (cmd_hdr.data_size)
cmd_hdr.data = NLMSG_DATA(nlh) + hdr_size;
execute_recv_command(&cmd_hdr);
}
#if DEBUG
static void dispmgr_nl_exit(void)
{
printk(KERN_INFO "kdispmgr: exiting hello module\n");
netlink_kernel_release(nl_sk);
g_pid = 0;
}
#endif
static int dispmgr_nl_init(void)
{
int ret = 0;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
nl_sk = netlink_kernel_create(&init_net,
NETLINK_DISPMGR,
0, nl_recv_msg, NULL, THIS_MODULE);
#else
struct netlink_kernel_cfg cfg = {
.groups = 0,
.input = nl_recv_msg,
};
nl_sk = netlink_kernel_create(&init_net, NETLINK_DISPMGR, &cfg);
#endif
if (!nl_sk) {
printk(KERN_ALERT "kdispmgr: error creating netlink socket.\n");
ret = -10;
} else {
printk(KERN_ALERT
"kdispmgr: netlink socket created successfully.\n");
ret = 0;
}
return ret;
}
void dispmgr_start(struct drm_device *dev)
{
pr_info("kdispmgr: display manager start.\n");
dispmgr_nl_init();
return;
}
/* this function is only called by dpms on or late resume function */
void dpstmgr_reg_restore_locked(struct mdfld_dsi_config *dsi_config)
{
struct mdfld_dsi_hw_context *ctx = NULL;
struct drm_psb_private *dev_priv = NULL;
struct mdfld_dsi_hw_registers *regs = NULL;
if (!dsi_config || !dsi_config->dev)
return;
ctx = &dsi_config->dsi_hw_context;
regs = &dsi_config->regs;
dev_priv = dsi_config->dev->dev_private;
if (!ospm_power_using_hw_begin(OSPM_DISPLAY_ISLAND,
OSPM_UHB_ONLY_IF_ON))
return;
PSB_WVDC32(ctx->histogram_intr_ctrl, regs->histogram_intr_ctrl_reg);
PSB_WVDC32(ctx->histogram_logic_ctrl, regs->histogram_logic_ctrl_reg);
PSB_WVDC32(ctx->aimg_enhance_bin, regs->aimg_enhance_bin_reg);
PSB_WVDC32(ctx->lvds_port_ctrl, regs->lvds_port_ctrl_reg);
ospm_power_using_hw_end(OSPM_DISPLAY_ISLAND);
}