// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ #include #include #include #include static DEFINE_SPINLOCK(lpm_plat_call_locker); static LIST_HEAD(lpm_callees); int lpm_callee_registry(struct lpm_callee *callee) { struct lpm_callee *pos; if (!callee) return -EINVAL; spin_lock(&lpm_plat_call_locker); list_for_each_entry(pos, &lpm_callees, list) { if (pos && (pos != callee) && (pos->uid == callee->uid)) { pos = NULL; break; } } if (pos) { callee->ref = 0; list_add(&callee->list, &lpm_callees); } spin_unlock(&lpm_plat_call_locker); return 0; } EXPORT_SYMBOL(lpm_callee_registry); int lpm_callee_unregistry(struct lpm_callee *callee) { int bRet = 0; struct lpm_callee *pos; if (!callee) return -EINVAL; spin_lock(&lpm_plat_call_locker); list_for_each_entry(pos, &lpm_callees, list) { if (pos && (pos->uid == callee->uid)) { if (!pos->ref) list_del(&pos->list); else bRet = -EPERM; break; } } spin_unlock(&lpm_plat_call_locker); return bRet; } EXPORT_SYMBOL(lpm_callee_unregistry); int lpm_callee_get_impl(int uid, const struct lpm_callee **callee) { struct lpm_callee *pos; if (!callee) return -EINVAL; *callee = NULL; spin_lock(&lpm_plat_call_locker); list_for_each_entry(pos, &lpm_callees, list) { if (pos && pos->uid == uid) { pos->ref++; *callee = pos; break; } } spin_unlock(&lpm_plat_call_locker); return *callee ? 0 : -EINVAL; } EXPORT_SYMBOL(lpm_callee_get_impl); int lpm_callee_put_impl(struct lpm_callee const *callee) { struct lpm_callee *pos; int ret = -EPERM; if (!callee) return -EINVAL; spin_lock(&lpm_plat_call_locker); list_for_each_entry(pos, &lpm_callees, list) { if (pos && (pos->uid == callee->uid)) { pos->ref--; ret = 0; break; } } spin_unlock(&lpm_plat_call_locker); return ret; } EXPORT_SYMBOL(lpm_callee_put_impl);