// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Samsung Electronics Co., Ltd. * Gwanghui Lee * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include #include #include #include "maptbl.h" #include "panel_debug.h" int maptbl_alloc_buffer(struct maptbl *m, size_t size) { if (!m || !size) return -EINVAL; m->arr = kzalloc(size, GFP_KERNEL); if (!m->arr) return -ENOMEM; return 0; } void maptbl_free_buffer(struct maptbl *m) { if (!m) return; kfree(m->arr); m->arr = NULL; } void maptbl_set_shape(struct maptbl *m, struct maptbl_shape *shape) { if (!m || !shape) return; memcpy(&m->shape, shape, sizeof(*shape)); } void maptbl_set_ops(struct maptbl *m, struct maptbl_ops *ops) { if (!m || !ops) return; memcpy(&m->ops, ops, sizeof(*ops)); } void maptbl_set_initialized(struct maptbl *m, bool initialized) { if (!m) return; m->initialized = initialized; } void maptbl_set_private_data(struct maptbl *m, void *priv) { if (!m) return; m->pdata = priv; } void *maptbl_get_private_data(struct maptbl *m) { if (!m) return NULL; return m->pdata; } /** * maptbl_create - create a struct maptbl structure * @name: pointer to a string for the name of this maptbl. * @shape: pointer to struct maptbl_shape for the shape of this maptbl. * @ops: pointer to struct maptbl_ops for the operations of this maptbl. * @init_data: pointer to buffer to initialize array buffer to be allocated. * @priv: pointer to private_data; passing when maptbl_init() invoked. * * This is used to create a struct maptbl pointer. * * Returns &struct maptbl pointer on success, or NULL on error. * * Note, the pointer created here is to be destroyed when finished by * making a call to maptbl_destroy(). */ struct maptbl *maptbl_create(char *name, struct maptbl_shape *shape, struct maptbl_ops *ops, void *init_data, void *priv) { struct maptbl *m; int ret; m = kzalloc(sizeof(*m), GFP_KERNEL); if (!m) return NULL; m->type = CMD_TYPE_MAP; m->name = name; maptbl_set_shape(m, shape); maptbl_set_ops(m, ops); maptbl_set_private_data(m, priv); if (!maptbl_get_sizeof_maptbl(m)) return m; ret = maptbl_alloc_buffer(m, maptbl_get_sizeof_maptbl(m)); if (ret < 0) { panel_err("failed to alloc maptbl buffer(ret:%d)\n", ret); goto err; } memcpy(m->arr, init_data, maptbl_get_sizeof_maptbl(m)); return m; err: kfree(m); return NULL; } EXPORT_SYMBOL(maptbl_create); /** * maptbl_clone - create a struct maptbl structure by source maptbl * @src: pointer to struct maptbl; used by passing argument to maptbl_create() function. * * This is used to create a struct maptbl pointer by source maptbl. * * Returns &struct maptbl pointer on success, or NULL on error. * * Note, the pointer created here is to be destroyed when finished by * making a call to maptbl_destroy(). */ struct maptbl *maptbl_clone(struct maptbl *src) { if (!src) return NULL; return maptbl_create(src->name, &src->shape, &src->ops, src->arr, maptbl_get_private_data(src)); } EXPORT_SYMBOL(maptbl_clone); /** * maptbl_deepcopy - copy members of struct maptbl structure from maptbl * @dst: pointer to destination struct maptbl * @src: pointer to source struct maptbl * * This is used to copy to destination maptbl from source maptbl. * * Returns &struct maptbl pointer to destination maptbl on success, or NULL on error. * * Note, the pointer to be free when finished by making a call to maptbl_free_buffer(). */ struct maptbl *maptbl_deepcopy(struct maptbl *dst, struct maptbl *src) { int ret; if (!dst || !src) return NULL; if (dst == src) return dst; dst->type = src->type; dst->name = src->name; maptbl_set_shape(dst, &src->shape); maptbl_set_ops(dst, &src->ops); maptbl_set_private_data(dst, maptbl_get_private_data(src)); maptbl_free_buffer(dst); if (!src->arr || !maptbl_get_sizeof_maptbl(src)) return dst; ret = maptbl_alloc_buffer(dst, maptbl_get_sizeof_maptbl(src)); if (ret < 0) { panel_err("failed to alloc maptbl buffer(ret:%d)\n", ret); return NULL; } memcpy(dst->arr, src->arr, maptbl_get_sizeof_maptbl(src)); return dst; } EXPORT_SYMBOL(maptbl_deepcopy); /** * maptbl_destroy - destroys a struct maptbl structure * @m: pointer to the struct maptbl that is to be destroyed * * Note, the pointer to be destroyed must have been created with a call * to maptbl_create(). */ void maptbl_destroy(struct maptbl *m) { maptbl_free_buffer(m); kfree(m); } EXPORT_SYMBOL(maptbl_destroy); int maptbl_get_indexof_n_dimen_element(struct maptbl *tbl, enum ndarray_dimen dimen, unsigned int indexof_element) { if (!tbl) return -EINVAL; if (indexof_element >= maptbl_get_countof_n_dimen_element(tbl, dimen)) { panel_err("%s: out of bound(indexof_%dD_element:%d >= countof_%dD_element:%d)\n", tbl->name, dimen + 1, indexof_element, dimen + 1, maptbl_get_countof_n_dimen_element(tbl, dimen)); return -EINVAL; } return maptbl_get_sizeof_n_dimen_element(tbl, dimen) * indexof_element; } EXPORT_SYMBOL(maptbl_get_indexof_n_dimen_element); int maptbl_get_indexof_box(struct maptbl *tbl, unsigned int indexof_element) { return maptbl_get_indexof_n_dimen_element(tbl, NDARR_4D, indexof_element); } EXPORT_SYMBOL(maptbl_get_indexof_box); int maptbl_get_indexof_layer(struct maptbl *tbl, unsigned int indexof_element) { return maptbl_get_indexof_n_dimen_element(tbl, NDARR_3D, indexof_element); } EXPORT_SYMBOL(maptbl_get_indexof_layer); int maptbl_get_indexof_row(struct maptbl *tbl, unsigned int indexof_element) { return maptbl_get_indexof_n_dimen_element(tbl, NDARR_2D, indexof_element); } EXPORT_SYMBOL(maptbl_get_indexof_row); int maptbl_get_indexof_col(struct maptbl *tbl, unsigned int indexof_element) { return maptbl_get_indexof_n_dimen_element(tbl, NDARR_1D, indexof_element); } EXPORT_SYMBOL(maptbl_get_indexof_col); int maptbl_4d_index(struct maptbl *tbl, int box, int layer, int row, int col) { int dimen, res = 0; int index, indexof_element; if (!tbl) return -EINVAL; maptbl_for_each_dimen(tbl, dimen) { if (dimen == NDARR_1D) indexof_element = col; else if (dimen == NDARR_2D) indexof_element = row; else if (dimen == NDARR_3D) indexof_element = layer; else if (dimen == NDARR_4D) indexof_element = box; index = maptbl_get_indexof_n_dimen_element(tbl, dimen, indexof_element); if (index < 0) return -EINVAL; res += index; } return res; } EXPORT_SYMBOL(maptbl_4d_index); int maptbl_index(struct maptbl *tbl, int layer, int row, int col) { if (!tbl) return -EINVAL; return maptbl_4d_index(tbl, 0, layer, row, col); } EXPORT_SYMBOL(maptbl_index); int maptbl_pos_to_index(struct maptbl *tbl, struct maptbl_pos *pos) { int dimen, res = 0; int indexof_element; if (!tbl || !pos) return -EINVAL; maptbl_for_each_dimen(tbl, dimen) { indexof_element = maptbl_get_indexof_n_dimen_element(tbl, dimen, pos->index[dimen]); if (indexof_element < 0) return -EINVAL; res += indexof_element; } return res; } EXPORT_SYMBOL(maptbl_pos_to_index); int maptbl_index_to_pos(struct maptbl *tbl, unsigned int index, struct maptbl_pos *pos) { int dimen; int sizeof_element; if (!tbl || !pos) return -EINVAL; if (index >= maptbl_get_sizeof_maptbl(tbl)) return -EINVAL; maptbl_for_each_dimen_reverse(tbl, dimen) { sizeof_element = maptbl_get_sizeof_n_dimen_element(tbl, dimen); if (sizeof_element <= 0) return -EINVAL; pos->index[dimen] = index / sizeof_element; index = index % sizeof_element; } return 0; } EXPORT_SYMBOL(maptbl_index_to_pos); bool maptbl_is_initialized(struct maptbl *tbl) { return (tbl && tbl->initialized); } EXPORT_SYMBOL(maptbl_is_initialized); bool maptbl_is_index_in_bound(struct maptbl *tbl, unsigned int index) { return (tbl && (index + maptbl_get_sizeof_copy(tbl) <= maptbl_get_sizeof_maptbl(tbl))); } EXPORT_SYMBOL(maptbl_is_index_in_bound); int maptbl_init(struct maptbl *tbl) { int ret; if (!tbl) return -EINVAL; if (!tbl->name) return -ENODATA; if (!tbl->ops.init) { panel_err("%s:no init callback\n", tbl->name); return -EINVAL; } ret = tbl->ops.init(tbl); if (ret < 0) { panel_err("%s:failed to init(ret:%d)\n", tbl->name, ret); return ret; } maptbl_set_initialized(tbl, true); return 0; } EXPORT_SYMBOL(maptbl_init); int maptbl_getidx(struct maptbl *tbl) { int index; if (!tbl) return -EINVAL; if (!tbl->ops.getidx) { panel_err("%s:no getidx callback\n", tbl->name); return -EINVAL; } if (!maptbl_is_initialized(tbl)) { panel_err("%s:not initialized\n", tbl->name); return -EINVAL; } index = tbl->ops.getidx(tbl); if (index < 0) { panel_err("%s:failed to getidx(ret:%d)\n", tbl->name, index); return -EINVAL; } if (!maptbl_is_index_in_bound(tbl, index)) { panel_err("%s:out of bound(index:%d, sizeof_copy:%d, sizeof_maptbl:%d)\n", tbl->name, index, maptbl_get_sizeof_copy(tbl), maptbl_get_sizeof_maptbl(tbl)); return -EINVAL; } return index; } EXPORT_SYMBOL(maptbl_getidx); int maptbl_copy(struct maptbl *tbl, u8 *dst) { if (!tbl || !dst) return -EINVAL; if (!tbl->ops.copy) { panel_err("%s:no copy callback\n", tbl->name); return -EINVAL; } if (!maptbl_is_initialized(tbl)) { panel_err("%s:not initialized\n", tbl->name); return -EINVAL; } tbl->ops.copy(tbl, dst); return 0; } EXPORT_SYMBOL(maptbl_copy); int maptbl_fill(struct maptbl *tbl, struct maptbl_pos *pos, u8 *src, size_t n) { u32 index; if (!tbl || !tbl->arr || !pos || !src || !n) { panel_err("invalid parameter\n"); return -EINVAL; } index = maptbl_pos_to_index(tbl, pos); if (maptbl_get_sizeof_maptbl(tbl) <= index) { panel_err("index(%d) exceed maptbl size\n", index); return -EINVAL; } if (maptbl_get_sizeof_row(tbl) < n) { panel_err("size(%ld) exceed row(%d) size\n", n, maptbl_get_sizeof_row(tbl)); return -EINVAL; } memcpy(tbl->arr + index, src, n); return 0; } EXPORT_SYMBOL(maptbl_fill); int maptbl_cmp_shape(struct maptbl *m1, struct maptbl *m2) { int dimen, res = 0; if (m1 == m2) return 0; if (!m1 || !m2) return !m1 ? -1 : 1; if ((res = maptbl_get_countof_dimen(m1) - maptbl_get_countof_dimen(m2)) != 0) return res; maptbl_for_each_dimen_reverse(m1, dimen) if ((res = maptbl_get_countof_n_dimen_element(m1, dimen) - maptbl_get_countof_n_dimen_element(m2, dimen)) != 0) break; return res; } EXPORT_SYMBOL(maptbl_cmp_shape); struct maptbl *maptbl_memcpy(struct maptbl *dst, struct maptbl *src) { if (!src || !dst) return NULL; if (!src->arr || !dst->arr) return NULL; if (maptbl_cmp_shape(src, dst)) { panel_err("failed to copy different shape of maptbl, src:%s(%d), dst:%s(%d)\n", src->name, maptbl_get_sizeof_maptbl(src), dst->name, maptbl_get_sizeof_maptbl(dst)); return NULL; } memcpy(dst->arr, src->arr, maptbl_get_sizeof_maptbl(dst)); return dst; } EXPORT_SYMBOL(maptbl_memcpy); int maptbl_snprintf_head(struct maptbl *tbl, char *buf, size_t size) { int i, len; if (!tbl || !buf || !size) return 0; len = snprintf(buf, size, "%dD-MAPTBL:%s", maptbl_get_countof_dimen(tbl), tbl->name); maptbl_for_each_dimen_reverse(tbl, i) len += snprintf(buf + len, size - len, "[%d]", maptbl_get_countof_n_dimen_element(tbl, i)); len += snprintf(buf + len, size - len, "\n"); return len; } int maptbl_snprintf_body(struct maptbl *tbl, char *buf, size_t size) { int box, layer, row, col, len = 0; char *space[MAX_NDARR_DIMEN] = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t", "\t\t\t\t\t\t", "\t\t\t\t\t\t\t"}; if (!tbl || !buf || !size) return 0; len += snprintf(buf + len, size - len, "\n"); maptbl_for_each_n_dimen_element(tbl, NDARR_4D, box) { if (maptbl_get_countof_dimen(tbl) >= 4) len += snprintf(buf + len, size - len, "%s[%d] = {\n", space[maptbl_get_countof_dimen(tbl) - 4], box); maptbl_for_each_n_dimen_element(tbl, NDARR_3D, layer) { if (maptbl_get_countof_dimen(tbl) >= 3) len += snprintf(buf + len, size - len, "%s[%d] = {\n", space[maptbl_get_countof_dimen(tbl) - 3], layer); maptbl_for_each_n_dimen_element(tbl, NDARR_2D, row) { if (maptbl_get_countof_dimen(tbl) >= 2) len += snprintf(buf + len, size - len, "%s[%d] = {\n", space[maptbl_get_countof_dimen(tbl) - 2], row); maptbl_for_each_n_dimen_element(tbl, NDARR_1D, col) { if (!(col % 8)) len += snprintf(buf + len, size - len, "%s", space[maptbl_get_countof_dimen(tbl) - 1]); len += snprintf(buf + len, size - len, "%02X", tbl->arr[maptbl_4d_index(tbl, box, layer, row, col)]); if (!((col + 1) % 8) ||(col + 1 == maptbl_get_countof_col(tbl))) len += snprintf(buf + len, size - len, "\n"); else len += snprintf(buf + len, size - len, " "); } if (maptbl_get_countof_dimen(tbl) >= 2) len += snprintf(buf + len, size - len, "%s},\n", space[maptbl_get_countof_dimen(tbl) - 2]); } if (maptbl_get_countof_dimen(tbl) >= 3) len += snprintf(buf + len, size - len, "%s},\n", space[maptbl_get_countof_dimen(tbl) - 3]); } if (maptbl_get_countof_dimen(tbl) >= 4) len += snprintf(buf + len, size - len, "%s},\n", space[maptbl_get_countof_dimen(tbl) - 4]); } return len; } int maptbl_snprintf_tail(struct maptbl *tbl, char *buf, size_t size) { if (!tbl || !buf || !size) return 0; return snprintf(buf, size, "=====================================\n"); } int maptbl_snprintf(struct maptbl *tbl, char *buf, size_t size) { int len; if (!tbl || !buf || !size) return 0; len = maptbl_snprintf_head(tbl, buf, size); len += maptbl_snprintf_body(tbl, buf + len, size - len); len += maptbl_snprintf_tail(tbl, buf + len, size - len); return len; } void maptbl_print(struct maptbl *tbl) { char buf[256] = { 0, }; if (panel_log_level < 7) return; maptbl_snprintf(tbl, buf, sizeof(buf)); pr_info("%s\n", buf); } EXPORT_SYMBOL(maptbl_print);