290 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.4 *5 * @File ctresource.c6 *7 * @Brief8 * This file contains the implementation of some generic helper functions.9 *10 * @Author Liu Chun11 * @Date May 15 200812 */13 14#include "ctresource.h"15#include "cthardware.h"16#include <linux/err.h>17#include <linux/slab.h>18 19#define AUDIO_SLOT_BLOCK_NUM 25620 21/* Resource allocation based on bit-map management mechanism */22static int23get_resource(u8 *rscs, unsigned int amount,24 unsigned int multi, unsigned int *ridx)25{26 int i, j, k, n;27 28 /* Check whether there are sufficient resources to meet request. */29 for (i = 0, n = multi; i < amount; i++) {30 j = i / 8;31 k = i % 8;32 if (rscs[j] & ((u8)1 << k)) {33 n = multi;34 continue;35 }36 if (!(--n))37 break; /* found sufficient contiguous resources */38 }39 40 if (i >= amount) {41 /* Can not find sufficient contiguous resources */42 return -ENOENT;43 }44 45 /* Mark the contiguous bits in resource bit-map as used */46 for (n = multi; n > 0; n--) {47 j = i / 8;48 k = i % 8;49 rscs[j] |= ((u8)1 << k);50 i--;51 }52 53 *ridx = i + 1;54 55 return 0;56}57 58static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx)59{60 unsigned int i, j, k, n;61 62 /* Mark the contiguous bits in resource bit-map as used */63 for (n = multi, i = idx; n > 0; n--) {64 j = i / 8;65 k = i % 8;66 rscs[j] &= ~((u8)1 << k);67 i++;68 }69 70 return 0;71}72 73int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx)74{75 int err;76 77 if (n > mgr->avail)78 return -ENOENT;79 80 err = get_resource(mgr->rscs, mgr->amount, n, ridx);81 if (!err)82 mgr->avail -= n;83 84 return err;85}86 87int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx)88{89 put_resource(mgr->rscs, n, idx);90 mgr->avail += n;91 92 return 0;93}94 95static const unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = {96 /* SRC channel is at Audio Ring slot 1 every 16 slots. */97 [SRC] = 0x1,98 [AMIXER] = 0x4,99 [SUM] = 0xc,100};101 102static int rsc_index(const struct rsc *rsc)103{104 return rsc->conj;105}106 107static int audio_ring_slot(const struct rsc *rsc)108{109 return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];110}111 112static void rsc_next_conj(struct rsc *rsc)113{114 unsigned int i;115 for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )116 i++;117 rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);118}119 120static void rsc_master(struct rsc *rsc)121{122 rsc->conj = rsc->idx;123}124 125static const struct rsc_ops rsc_generic_ops = {126 .index = rsc_index,127 .output_slot = audio_ring_slot,128 .master = rsc_master,129 .next_conj = rsc_next_conj,130};131 132int133rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw)134{135 int err = 0;136 137 rsc->idx = idx;138 rsc->conj = idx;139 rsc->type = type;140 rsc->msr = msr;141 rsc->hw = hw;142 rsc->ops = &rsc_generic_ops;143 if (!hw) {144 rsc->ctrl_blk = NULL;145 return 0;146 }147 148 switch (type) {149 case SRC:150 err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk);151 break;152 case AMIXER:153 err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk);154 break;155 case SRCIMP:156 case SUM:157 case DAIO:158 break;159 default:160 dev_err(((struct hw *)hw)->card->dev,161 "Invalid resource type value %d!\n", type);162 return -EINVAL;163 }164 165 if (err) {166 dev_err(((struct hw *)hw)->card->dev,167 "Failed to get resource control block!\n");168 return err;169 }170 171 return 0;172}173 174int rsc_uninit(struct rsc *rsc)175{176 if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) {177 switch (rsc->type) {178 case SRC:179 rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk);180 break;181 case AMIXER:182 rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk);183 break;184 case SUM:185 case DAIO:186 break;187 default:188 dev_err(((struct hw *)rsc->hw)->card->dev,189 "Invalid resource type value %d!\n",190 rsc->type);191 break;192 }193 194 rsc->hw = rsc->ctrl_blk = NULL;195 }196 197 rsc->idx = rsc->conj = 0;198 rsc->type = NUM_RSCTYP;199 rsc->msr = 0;200 201 return 0;202}203 204int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type,205 unsigned int amount, struct hw *hw)206{207 int err = 0;208 209 mgr->type = NUM_RSCTYP;210 211 mgr->rscs = kzalloc(DIV_ROUND_UP(amount, 8), GFP_KERNEL);212 if (!mgr->rscs)213 return -ENOMEM;214 215 switch (type) {216 case SRC:217 err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk);218 break;219 case SRCIMP:220 err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk);221 break;222 case AMIXER:223 err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk);224 break;225 case DAIO:226 err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk);227 break;228 case SUM:229 break;230 default:231 dev_err(hw->card->dev,232 "Invalid resource type value %d!\n", type);233 err = -EINVAL;234 goto error;235 }236 237 if (err) {238 dev_err(hw->card->dev,239 "Failed to get manager control block!\n");240 goto error;241 }242 243 mgr->type = type;244 mgr->avail = mgr->amount = amount;245 mgr->hw = hw;246 247 return 0;248 249error:250 kfree(mgr->rscs);251 return err;252}253 254int rsc_mgr_uninit(struct rsc_mgr *mgr)255{256 kfree(mgr->rscs);257 mgr->rscs = NULL;258 259 if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) {260 switch (mgr->type) {261 case SRC:262 mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk);263 break;264 case SRCIMP:265 mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk);266 break;267 case AMIXER:268 mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk);269 break;270 case DAIO:271 mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk);272 break;273 case SUM:274 break;275 default:276 dev_err(((struct hw *)mgr->hw)->card->dev,277 "Invalid resource type value %d!\n",278 mgr->type);279 break;280 }281 282 mgr->hw = mgr->ctrl_blk = NULL;283 }284 285 mgr->type = NUM_RSCTYP;286 mgr->avail = mgr->amount = 0;287 288 return 0;289}290