webprobe/ \
task_data/ \
preload/ \
- fbiprobe/
+ fbiprobe/ \
+ wsp/
install -m 666 task_data/swap_task_data.ko -t %{buildroot}/opt/swap/sdk
install -m 666 preload/swap_preload.ko -t %{buildroot}/opt/swap/sdk
install -m 666 fbiprobe/swap_fbiprobe.ko -t %{buildroot}/opt/swap/sdk
+install -m 666 wsp/swap_wsp.ko -t %{buildroot}/opt/swap/sdk
%files
%defattr(-,root,root)
/opt/swap/sdk/swap_task_data.ko
/opt/swap/sdk/swap_preload.ko
/opt/swap/sdk/swap_fbiprobe.ko
+/opt/swap/sdk/swap_wsp.ko
free_pfg(pfg);
}
}
+EXPORT_SYMBOL_GPL(put_pf_group);
/**
* @brief Register prober for pf_grpup struct
MSG_PROC_COMM = 0x0014,
MSG_WEB_FUNCTION_ENTRY = 0x0015,
MSG_WEB_FUNCTION_EXIT = 0x0016,
+ MSG_WSP = 0x001a,
MSG_FBI = 0x0020
};
--- /dev/null
+EXTRA_CFLAGS := $(extra_cflags)
+
+obj-m := swap_wsp.o
+swap_wsp-y := wsp_module.o \
+ wsp_msg.o \
+ wsp_debugfs.o \
+ wsp.o \
+ wsp_res.o
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <us_manager/sspt/sspt.h>
+#include <us_manager/probes/probe_info_new.h>
+#include "wsp.h"
+#include "wsp_res.h"
+#include "wsp_msg.h"
+
+
+struct wsp_probe {
+ const char *name;
+ struct probe_new probe;
+};
+
+struct wsp_bin {
+ const char *name;
+ unsigned long cnt;
+ struct wsp_probe *probe_array;
+};
+
+
+static const char webapp_path[] = "/usr/bin/WebProcess";
+static const char ewebkit_path[] = "/usr/lib/libewebkit2.so";
+
+
+#define WSP_PROBE_MAKE(_name, _info) \
+{ \
+ .name = _name, \
+ .probe.offset = 0, \
+ .probe.info = _info \
+}
+
+
+static const char *strdup_from_user(const char __user *user_s)
+{
+ enum { max_str_len = 1024 };
+ char *str;
+ int len_s, ret;
+
+ len_s = strnlen_user(user_s, max_str_len - 1);
+ str = kmalloc(len_s + 1, GFP_ATOMIC);
+ if (str == NULL)
+ return NULL;
+
+ ret = strncpy_from_user(str, user_s, len_s);
+ if (ret < 0) {
+ kfree(str);
+ return NULL;
+ }
+
+ str[ret] = '\0';
+
+ return str;
+}
+
+static void do_res_processing_begin(void *data, void *ptr, enum wsp_res_t type)
+{
+ struct wsp_res **save_res = (struct wsp_res **)data;
+ struct wsp_res *res;
+
+ res = wsp_res_find(ptr, type);
+
+ /* save res pointer */
+ *save_res = res;
+ if (res) {
+ wsp_msg(WSP_RES_PROC_BEGIN, res->id, NULL);
+ wsp_res_stat_set_next(res, WRS_ADD_DATA);
+ }
+}
+
+static void do_res_processing_end(struct wsp_res *res)
+{
+ wsp_msg(WSP_RES_PROC_END, res->id, NULL);
+}
+
+static void do_res_finish(struct wsp_res *res)
+{
+ wsp_msg(WSP_RES_LOAD_END, res->id, NULL);
+ wsp_res_stat_set_next(res, WRS_FINISH);
+ wsp_res_del(res);
+}
+
+
+/*
+ * soup_req
+ */
+static int soup_req_handle(struct kprobe *p, struct pt_regs *regs)
+{
+ enum { max_str_len = 512 };
+ const char *path;
+ struct wsp_res *res;
+
+ res = wsp_res_last();
+ if (res == NULL) {
+ pr_err("last wsp_res is not found\n");
+ return 0;
+ }
+
+ path = strdup_from_user((const char __user *)swap_get_uarg(regs, 1));
+ wsp_msg(WSP_RES_LOAD_BEGIN, res->id, path);
+ wsp_res_stat_set_next(res, WRS_SOUP_REQ);
+ kfree(path);
+
+ return 0;
+}
+
+static struct probe_info_new soup_req = MAKE_UPROBE(soup_req_handle);
+
+
+/*
+ * main_res_req
+ */
+static int mres_req_handle(struct kprobe *p, struct pt_regs *regs)
+{
+ void *ptr = (void *)swap_get_uarg(regs, 0);
+ struct wsp_res *res;
+
+ res = wsp_res_new(ptr, WR_MAIN);
+ wsp_res_stat_set_next(res, WRS_WILL_REQ);
+
+ return 0;
+}
+
+static struct probe_info_new mres_req = MAKE_UPROBE(mres_req_handle);
+
+
+/*
+ * main_res_add_data
+ */
+
+static int mres_adata_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+ void *ptr = (void *)swap_get_uarg(regs, 0);
+
+ do_res_processing_begin(ri->data, ptr, WR_MAIN);
+
+ return 0;
+}
+
+static int mres_adata_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+ struct wsp_res *res = *(struct wsp_res **)ri->data;
+
+ if (res)
+ do_res_processing_end(res);
+
+ return 0;
+}
+
+static struct probe_info_new mres_adata =
+ MAKE_URPROBE(mres_adata_eh, mres_adata_rh,
+ sizeof(struct wsp_res *));
+
+
+/*
+ * main_res_finish
+ */
+static int mres_finish_handle(struct kprobe *p, struct pt_regs *regs)
+{
+ void *ptr = (void *)swap_get_uarg(regs, 0);
+ struct wsp_res *res;
+
+ res = wsp_res_find(ptr, WR_MAIN);
+ if (res) {
+ wsp_current_set_stat(TDS_FINISH_MAIN_LOAD);
+ do_res_finish(res);
+ }
+
+ return 0;
+}
+
+static struct probe_info_new mres_finish = MAKE_UPROBE(mres_finish_handle);
+
+
+/*
+ * res_request
+ */
+static int res_request_handle(struct kprobe *p, struct pt_regs *regs)
+{
+ void *ptr = (void *)swap_get_uarg(regs, 0);
+ struct wsp_res *res;
+
+ res = wsp_res_last();
+ if (res) {
+ if (res->type == WR_MAIN && res->stat == WRS_WILL_REQ)
+ /* skip */
+ return 0;
+ }
+
+ res = wsp_res_new(ptr, WR_ANY);
+ wsp_res_stat_set_next(res, WRS_WILL_REQ);
+
+ return 0;
+}
+
+static struct probe_info_new res_request = MAKE_UPROBE(res_request_handle);
+
+
+/*
+ * res_finish
+ */
+static int res_finish_ehandle(struct uretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ void *ptr = (void *)swap_get_uarg(regs, 0);
+
+ do_res_processing_begin(ri->data, ptr, WR_ANY);
+
+ return 0;
+}
+
+static int res_finish_rhandle(struct uretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ struct wsp_res *res = *(struct wsp_res **)ri->data;
+
+ if (res) {
+ do_res_processing_end(res);
+ do_res_finish(res);
+ }
+
+ return 0;
+}
+
+static struct probe_info_new res_finish =
+ MAKE_URPROBE(res_finish_ehandle, res_finish_rhandle,
+ sizeof(struct wsp_res *));
+
+
+/*
+ * redraw
+ */
+static int redraw_eh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+ enum tdata_stat stat;
+
+ stat = wsp_current_get_stat();
+
+ if (stat == TDS_FINISH_MAIN_LOAD)
+ wsp_msg(WSP_DRAW_BEGIN, 0, NULL);
+
+ return 0;
+}
+
+static int redraw_rh(struct uretprobe_instance *ri, struct pt_regs *regs)
+{
+ if (wsp_current_get_stat() == TDS_FINISH_MAIN_LOAD) {
+ wsp_current_set_stat(TDS_DRAW);
+ wsp_msg(WSP_DRAW_END, 0, NULL);
+ }
+
+ return 0;
+}
+
+static struct probe_info_new redraw = MAKE_URPROBE(redraw_eh, redraw_rh, 0);
+
+
+static struct wsp_probe ewebkit_probe_array[] = {
+ /* plt */
+ /* soup_requester_request@plt */
+ WSP_PROBE_MAKE("soup_requester_request@plt", &soup_req),
+
+ /* main_res */
+ /* WebCore::MainResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
+ WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &mres_req),
+ /* WebCore::MainResourceLoader::addData(char const*, int, bool) */
+ WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader7addDataEPKcib", &mres_adata),
+ /* WebCore::MainResourceLoader::didFinishLoading(double) */
+ WSP_PROBE_MAKE("_ZN7WebCore18MainResourceLoader16didFinishLoadingEd", &mres_finish),
+
+
+ /* res */
+ /* WebCore::ResourceLoader::willSendRequest(WebCore::ResourceRequest&, WebCore::ResourceResponse const&) */
+ WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader15willSendRequestERNS_15ResourceRequestERKNS_16ResourceResponseE", &res_request),
+ /* WebCore::ResourceLoader::didFinishLoading(WebCore::ResourceHandle*, double) */
+ WSP_PROBE_MAKE("_ZN7WebCore14ResourceLoader16didFinishLoadingEPNS_14ResourceHandleEd", &res_finish),
+
+
+ /* redraw */
+ /* WebKit::LayerTreeCoordinator::flushPendingLayerChanges() */
+ WSP_PROBE_MAKE("_ZN6WebKit20LayerTreeCoordinator24flushPendingLayerChangesEv", &redraw),
+};
+
+enum {
+ ewebkit_probes_cnt =
+ sizeof(ewebkit_probe_array) / sizeof(struct wsp_probe)
+};
+
+static struct wsp_bin ewebkit = {
+ .name = ewebkit_path,
+ .cnt = ewebkit_probes_cnt,
+ .probe_array = ewebkit_probe_array
+};
+
+
+/* check ewebkit_probe_array on init address */
+static bool wsp_is_addr_init(void)
+{
+ int i;
+
+ for (i = 0; i < ewebkit_probes_cnt; ++i)
+ if (ewebkit_probe_array[i].probe.offset == 0)
+ return false;
+
+ return true;
+}
+
+
+static int wsp_probe_register(struct pf_group *pfg, struct dentry *dentry,
+ struct wsp_probe *wsp_probe)
+{
+ struct probe_new *probe_new = &wsp_probe->probe;
+
+ return pin_register(probe_new, pfg, dentry);
+}
+
+static void wsp_probe_unregister(struct pf_group *pfg, struct dentry *dentry,
+ struct wsp_probe *wsp_probe)
+{
+ struct probe_new *probe_new = &wsp_probe->probe;
+
+ pin_unregister(probe_new, pfg, dentry);
+}
+
+
+
+
+static int wsp_bin_register(struct pf_group *pfg, struct wsp_bin *bin)
+{
+ int i, ret;
+ struct dentry *dentry;
+
+ dentry = dentry_by_path(bin->name);
+ if (dentry == NULL) {
+ pr_err("dentry not found (path='%s'\n", bin->name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < bin->cnt; ++i) {
+ struct wsp_probe *p = &bin->probe_array[i];
+
+ ret = wsp_probe_register(pfg, dentry, p);
+ if (ret) {
+ pr_err("ERROR: wsp_probe_register, addr=%lx ret=%d\n",
+ p->probe.offset, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void wsp_bin_unregister(struct pf_group *pfg, struct wsp_bin *bin)
+{
+ int i;
+ struct dentry *dentry;
+
+ dentry = dentry_by_path(bin->name);
+ for (i = 0; i < bin->cnt; ++i)
+ wsp_probe_unregister(pfg, dentry, &bin->probe_array[i]);
+}
+
+
+static struct pf_group *g_pfg;
+
+static int wsp_app_register(void)
+{
+ struct dentry *dentry;
+
+ dentry = dentry_by_path(webapp_path);
+ if (dentry == NULL) {
+ pr_err("dentry not found (path='%s'\n", webapp_path);
+ return -EINVAL;
+ }
+
+ g_pfg = get_pf_group_by_dentry(dentry, (void *)dentry);
+ if (g_pfg == NULL) {
+ pr_err("g_pfg is NULL (by dentry=%p)\n", dentry);
+ return -ENOMEM;
+ }
+
+ return wsp_bin_register(g_pfg, &ewebkit);
+}
+
+static void wsp_app_unregister(void)
+{
+ wsp_bin_unregister(g_pfg, &ewebkit);
+ put_pf_group(g_pfg);
+}
+
+
+static int do_wsp_on(void)
+{
+ int ret;
+
+ ret = wsp_res_init();
+ if (ret)
+ return ret;
+
+ ret = wsp_app_register();
+ if (ret)
+ wsp_res_exit();
+
+ return ret;
+}
+
+static void do_wsp_off(void)
+{
+ wsp_app_unregister();
+ wsp_res_exit();
+}
+
+
+static enum wsp_mode g_mode = WSP_OFF;
+static DEFINE_MUTEX(g_mode_mutex);
+
+int wsp_set_addr(const char *name, unsigned long offset)
+{
+ int i, ret = 0;
+
+ if (mutex_trylock(&g_mode_mutex) == 0)
+ return -EBUSY;
+
+ for (i = 0; i < ewebkit_probes_cnt; ++i) {
+ if (0 == strcmp(name, ewebkit_probe_array[i].name)) {
+ ewebkit_probe_array[i].probe.offset = offset;
+ goto unlock;
+ }
+ }
+
+ ret = -EINVAL;
+
+unlock:
+ mutex_unlock(&g_mode_mutex);
+ return ret;
+}
+
+int wsp_set_mode(enum wsp_mode mode)
+{
+ int ret = 0;
+
+ mutex_lock(&g_mode_mutex);
+ switch (mode) {
+ case WSP_ON:
+ if (g_mode == WSP_ON) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = wsp_is_addr_init() ? do_wsp_on() : -EPERM;
+ break;
+ case WSP_OFF:
+ if (g_mode == WSP_OFF) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ do_wsp_off();
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+unlock:
+ if (ret == 0)
+ g_mode = mode;
+
+ mutex_unlock(&g_mode_mutex);
+ return ret;
+}
+
+enum wsp_mode wsp_get_mode(void)
+{
+ return g_mode;
+}
+
+int wsp_init(void)
+{
+ return 0;
+}
+
+void wsp_exit(void)
+{
+ wsp_set_mode(WSP_OFF);
+}
--- /dev/null
+#ifndef _WSP_H
+#define _WSP_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+enum wsp_mode {
+ WSP_ON,
+ WSP_OFF
+};
+
+
+int wsp_set_addr(const char *name, unsigned long offset);
+
+int wsp_set_mode(enum wsp_mode mode);
+enum wsp_mode wsp_get_mode(void);
+
+int wsp_init(void);
+void wsp_exit(void);
+
+
+#endif /* _WSP_H */
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <master/swap_debugfs.h>
+#include "wsp.h"
+
+
+static int do_write_cmd(const char *buf, size_t count)
+{
+ int n, ret = 0;
+ char *name;
+ unsigned long offset;
+
+ name = kmalloc(count, GFP_KERNEL);
+ if (name == NULL)
+ return -ENOMEM;
+
+ n = sscanf(buf, "%lx %s", &offset, name);
+ if (n != 2) {
+ ret = -EINVAL;
+ goto free_name;
+ }
+
+ ret = wsp_set_addr(name, offset);
+
+free_name:
+ kfree(name);
+ return ret;
+}
+
+/* ============================================================================
+ * === DEBUGFS FOR ENABLE ===
+ * ============================================================================
+ */
+static ssize_t write_cmd(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ enum { max_count = 1024 };
+ int ret;
+ char *buf;
+
+ if (count > max_count)
+ return -ENOMEM;
+
+ buf = kmalloc(count + 1, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, user_buf, count)) {
+ ret = -EFAULT;
+ goto free_buf;
+ }
+
+ buf[count] = '\0';
+ ret = do_write_cmd(buf, count);
+
+free_buf:
+ kfree(buf);
+ return ret ? ret : count;
+}
+
+static const struct file_operations fops_cmd = {
+ .write = write_cmd,
+ .llseek = default_llseek,
+};
+
+
+
+
+/* ============================================================================
+ * === DEBUGFS FOR ENABLE ===
+ * ============================================================================
+ */
+static ssize_t read_enabled(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[2];
+
+ buf[0] = wsp_get_mode() == WSP_OFF ? '0' : '1';
+ buf[1] = '\n';
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int ret = 0;
+ char buf[32];
+ size_t buf_size;
+
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ buf[buf_size] = '\0';
+ switch (buf[0]) {
+ case '1':
+ ret = wsp_set_mode(WSP_ON);
+ break;
+ case '0':
+ ret = wsp_set_mode(WSP_OFF);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static const struct file_operations fops_enabled = {
+ .read = read_enabled,
+ .write = write_enabled,
+ .llseek = default_llseek,
+};
+
+
+static struct dentry *wsp_dir;
+
+void wsp_debugfs_exit(void)
+{
+ if (wsp_dir)
+ debugfs_remove_recursive(wsp_dir);
+
+ wsp_dir = NULL;
+}
+
+int wsp_debugfs_init(void)
+{
+ struct dentry *dentry;
+
+ dentry = swap_debugfs_getdir();
+ if (dentry == NULL)
+ return -ENOENT;
+
+ wsp_dir = debugfs_create_dir("wsp", dentry);
+ if (wsp_dir == NULL)
+ return -ENOMEM;
+
+ dentry = debugfs_create_file("enabled", 0600, wsp_dir, NULL,
+ &fops_enabled);
+ if (dentry == NULL)
+ goto fail;
+
+ dentry = debugfs_create_file("cmd", 0600, wsp_dir, NULL, &fops_cmd);
+ if (dentry == NULL)
+ goto fail;
+
+ return 0;
+
+fail:
+ wsp_debugfs_exit();
+ return -ENOMEM;
+}
--- /dev/null
+#ifndef _WSP_DEBUGFS_H
+#define _WSP_DEBUGFS_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+int wsp_debugfs_init(void);
+void wsp_debugfs_exit(void);
+
+
+#endif /* _WSP_DEBUGFS_H */
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2014
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <master/swap_initializer.h>
+#include "wsp.h"
+#include "wsp_debugfs.h"
+
+
+SWAP_LIGHT_INIT_MODULE(NULL, wsp_init, wsp_exit,
+ wsp_debugfs_init, wsp_debugfs_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <writer/swap_msg.h>
+#include "wsp_msg.h"
+
+
+/*
+ * MSG_WSP (payload):
+ * +-------------+----------+----------+
+ * | name | type | lenght |
+ * +-------------+----------+----------+
+ * | PID | int | 4 |
+ * | wsp_id | int | 4 |
+ * | wsp_payload | variable | variable |
+ * +-------------+----------+----------+
+
+ * wsp_id:
+ * - WSP_RES_LOAD_BEGIN = 0x0001
+ * - WSP_RES_LOAD_END = 0x0002
+ * - WSP_RES_PROC_BEGIN = 0x0003
+ * - WSP_RES_PROC_END = 0x0004
+ * - WSP_DRAW_BEGIN = 0x0005
+ * - WSP_DRAW_END = 0x0006
+ *
+ * wsp_payload:
+ *
+ * 1. WSP_RES_LOAD_BEGIN:
+ * +--------+--------+----------+
+ * | name | type | lenght |
+ * +--------+--------+----------+
+ * | res_id | int | 4 |
+ * | path | string | variable |
+ * +--------+--------+----------+
+ *
+ * 2. WSP_RES_LOAD_END, WSP_RES_PROC_BEGIN, WSP_RES_PROC_END:
+ * +--------+--------+----------+
+ * | name | type | lenght |
+ * +--------+--------+----------+
+ * | res_id | int | 4 |
+ * +--------+--------+----------+
+ *
+ * 3. WSP_DRAW_BEGIN, WSP_DRAW_END:
+ * no wsp_payload
+ */
+
+static int pack_wsp_msg(void *data, size_t size, enum wsp_id id,
+ u32 res_id, const char *path)
+{
+ size_t len;
+ const size_t old_size = size;
+
+ /* write PID */
+ *(u32 *)data = (u32)current->tgid;
+ data += 4;
+ size -= 4;
+
+ /* write wsp_id */
+ *(u32 *)data = (u32)id;
+ data += 4;
+ size -= 4;
+
+ /* pack wsp_payload */
+ switch (id) {
+ case WSP_RES_LOAD_BEGIN:
+ len = strlen(path) + 1;
+ if (size < len + 4)
+ return -ENOMEM;
+
+ /* '+ 4' - skip space for res_id */
+ memcpy(data + 4, path, len);
+ size -= len;
+ case WSP_RES_LOAD_END:
+ case WSP_RES_PROC_BEGIN:
+ case WSP_RES_PROC_END:
+ /* write res_id */
+ *(u32 *)data = res_id;
+ size -= 4;
+ break;
+
+ case WSP_DRAW_BEGIN:
+ case WSP_DRAW_END:
+ break;
+
+ default:
+ printk(KERN_ERR "unknown wsp_id: id=%u\n", (unsigned)id);
+ return -EINVAL;
+ }
+
+ return old_size - size;
+}
+
+void wsp_msg(enum wsp_id id, u32 res_id, const char *path)
+{
+ int ret;
+ void *data;
+ size_t size;
+ struct swap_msg *m;
+
+ m = swap_msg_get(MSG_WSP);
+ data = swap_msg_payload(m);
+ size = swap_msg_size(m);
+ ret = pack_wsp_msg(data, size, id, res_id, path);
+ if (ret < 0) {
+ printk(KERN_ERR "error MSG_WSP packing, ret=%d\n", ret);
+ goto put_msg;
+ }
+
+ swap_msg_flush(m, ret);
+
+put_msg:
+ swap_msg_put(m);
+}
--- /dev/null
+#ifndef _WSP_MSG_H
+#define _WSP_MSG_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+
+
+enum wsp_id {
+ WSP_RES_LOAD_BEGIN = 0x0001,
+ WSP_RES_LOAD_END = 0x0002,
+ WSP_RES_PROC_BEGIN = 0x0003,
+ WSP_RES_PROC_END = 0x0004,
+ WSP_DRAW_BEGIN = 0x0005,
+ WSP_DRAW_END = 0x0006
+};
+
+
+void wsp_msg(enum wsp_id id, u32 res_id, const char *path);
+
+
+#endif /* _WSP_MSG_H */
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2016
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/slab.h>
+#include <linux/atomic.h>
+#include "wsp_res.h"
+
+static atomic_t wsp_res_count;
+
+static int wsp_tdata_get_id(void)
+{
+ return atomic_inc_return(&wsp_res_count);
+}
+
+static struct wsp_tdata *g_tdata;
+
+/* FIXME: get_tdata() need receive for each processes */
+static struct wsp_tdata *get_tdata(void)
+{
+ return g_tdata;
+}
+
+
+
+
+
+/* ============================================================================
+ * = wsp_tdata =
+ * ============================================================================
+ */
+struct wsp_tdata {
+ struct list_head res_list;
+ spinlock_t lock;
+
+ enum tdata_stat stat;
+};
+
+static struct wsp_res *wsp_tdata_new_res(struct wsp_tdata *d, void *ptr,
+ enum wsp_res_t type)
+{
+ struct wsp_res *res;
+
+ res = kmalloc(sizeof(*res), GFP_ATOMIC);
+ if (res) {
+ INIT_LIST_HEAD(&res->list);
+ res->ptr = ptr;
+ res->id = wsp_tdata_get_id();
+ res->type = type;
+ res->stat = WRS_NEW;
+
+ /* add to list */
+ spin_lock(&d->lock);
+ list_add(&res->list, &d->res_list);
+ spin_unlock(&d->lock);
+ }
+
+ return res;
+}
+
+static void wsp_tdata_del_res(struct wsp_res *res)
+{
+ list_del(&res->list);
+ kfree(res);
+}
+
+static struct wsp_tdata *wsp_tdata_create(void)
+{
+ struct wsp_tdata *d;
+
+ d = kmalloc(sizeof(*d), GFP_ATOMIC);
+ if (d) {
+ INIT_LIST_HEAD(&d->res_list);
+ spin_lock_init(&d->lock);
+ d->stat = TDS_NEW;
+ }
+
+ return d;
+}
+
+static void wsp_tdata_destroy(struct wsp_tdata *d)
+{
+ struct wsp_res *res, *n;
+
+ spin_lock(&d->lock);
+ list_for_each_entry_safe(res, n, &d->res_list, list)
+ wsp_tdata_del_res(res);
+ spin_unlock(&d->lock);
+}
+
+static struct wsp_res *wsp_tdata_last_res(struct wsp_tdata *d)
+{
+ struct wsp_res *res;
+
+ spin_lock(&d->lock);
+ res = list_first_entry_or_null(&d->res_list, struct wsp_res, list);
+ spin_unlock(&d->lock);
+
+ return res;
+}
+
+struct wsp_res *wsp_tdata_find_res(struct wsp_tdata *data, void *ptr,
+ enum wsp_res_t type)
+{
+ struct wsp_res *res;
+
+ list_for_each_entry(res, &data->res_list, list) {
+ if (res->type != type)
+ continue;
+
+ if (res->ptr == ptr) {
+ if (res->stat == WRS_ERR) {
+ pr_err("ERR: something went wrong\n");
+ return NULL;
+ }
+
+ return res;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+
+/* ============================================================================
+ * = wsp_current_[get/set]_stat() =
+ * ============================================================================
+ */
+enum tdata_stat wsp_current_get_stat(void)
+{
+ struct wsp_tdata *d;
+
+ d = get_tdata();
+ if (d)
+ return d->stat;
+ else
+ pr_err("ERR: no current tdata\n");
+
+ return TDS_ERR;
+}
+
+void wsp_current_set_stat(enum tdata_stat stat)
+{
+ struct wsp_tdata *d;
+
+ d = get_tdata();
+ if (d)
+ d->stat = stat;
+ else
+ pr_err("ERR: no current tdata\n");
+}
+
+
+
+
+
+/* ============================================================================
+ * = wsp_res =
+ * ============================================================================
+ */
+struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type)
+{
+ struct wsp_tdata *data;
+
+ data = get_tdata();
+ if (data == NULL) {
+ pr_err("ERR: no current tdata\n");
+ return NULL;
+ }
+
+
+ return wsp_tdata_new_res(data, ptr, type);
+}
+
+void wsp_res_del(struct wsp_res *res)
+{
+ wsp_tdata_del_res(res);
+}
+
+struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type)
+{
+ struct wsp_tdata *data;
+
+ data = get_tdata();
+ if (data == NULL) {
+ pr_err("ERR: no current tdata\n");
+ return NULL;
+ }
+
+ return wsp_tdata_find_res(data, ptr, type);
+}
+
+struct wsp_res *wsp_res_last(void)
+{
+ struct wsp_tdata *d;
+
+ d = get_tdata();
+ if (d == NULL) {
+ pr_err("ERR: no current tdata\n");
+ return NULL;
+ }
+
+ return wsp_tdata_last_res(d);
+}
+
+int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat)
+{
+ switch (res->stat) {
+ case WRS_NEW:
+ if (stat == WRS_WILL_REQ) {
+ res->stat = stat;
+ return 0;
+ }
+ break;
+
+ case WRS_WILL_REQ:
+ if (stat == WRS_SOUP_REQ) {
+ res->stat = stat;
+ return 0;
+ }
+ break;
+
+ case WRS_SOUP_REQ:
+ case WRS_ADD_DATA:
+ if (stat == WRS_ADD_DATA || stat == WRS_FINISH) {
+ res->stat = stat;
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ pr_err("ERR: set_next_stat from %d to %d [id=%d]\n",
+ res->stat, stat, res->id);
+
+ res->stat = WRS_ERR;
+
+ return -1;
+}
+
+
+
+
+
+/* ============================================================================
+ * = init/exit() =
+ * ============================================================================
+ */
+int wsp_res_init(void)
+{
+ g_tdata = wsp_tdata_create();
+ if (g_tdata == NULL)
+ return -ENOMEM;
+
+ atomic_set(&wsp_res_count, 0);
+
+ return 0;
+}
+
+void wsp_res_exit(void)
+{
+ wsp_tdata_destroy(g_tdata);
+ g_tdata = NULL;
+}
--- /dev/null
+#ifndef _WSP_TDATA_H
+#define _WSP_TDATA_H
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) Samsung Electronics, 2015
+ *
+ * 2015 Vyacheslav Cherkashin <v.cherkashin@samsung.com>
+ *
+ */
+
+
+#include <linux/types.h>
+
+
+enum tdata_stat {
+ TDS_ERR,
+ TDS_NEW,
+ TDS_FINISH_MAIN_LOAD,
+ TDS_DRAW
+};
+
+enum wsp_res_t {
+ WR_NONE,
+ WR_MAIN,
+ WR_ANY
+};
+
+enum wsp_res_stat {
+ WRS_NEW,
+ WRS_WILL_REQ,
+ WRS_SOUP_REQ,
+ WRS_ADD_DATA,
+ WRS_FINISH,
+ WRS_ERR
+};
+
+struct wsp_res {
+ struct list_head list;
+ void *ptr;
+ int id;
+ enum wsp_res_t type;
+ enum wsp_res_stat stat;
+};
+
+
+enum tdata_stat wsp_current_get_stat(void);
+void wsp_current_set_stat(enum tdata_stat stat);
+
+struct wsp_res *wsp_res_new(void *ptr, enum wsp_res_t type);
+void wsp_res_del(struct wsp_res *res);
+
+struct wsp_res *wsp_res_last(void);
+struct wsp_res *wsp_res_find(void *ptr, enum wsp_res_t type);
+
+int wsp_res_stat_set_next(struct wsp_res *res, enum wsp_res_stat stat);
+
+int wsp_res_init(void);
+void wsp_res_exit(void);
+
+
+#endif /* _WSP_TDATA_H */