1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. 4 * 5 * @File ctresource.c 6 * 7 * @Brief 8 * This file contains the implementation of some generic helper functions. 9 * 10 * @Author Liu Chun 11 * @Date May 15 2008 12 */ 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 256 20 21 /* Resource allocation based on bit-map management mechanism */ 22 static int 23 get_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 58 static 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 73 int 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 87 int 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 95 static 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 102 static int rsc_index(const struct rsc *rsc) 103 { 104 return rsc->conj; 105 } 106 107 static int audio_ring_slot(const struct rsc *rsc) 108 { 109 return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type]; 110 } 111 112 static 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 120 static void rsc_master(struct rsc *rsc) 121 { 122 rsc->conj = rsc->idx; 123 } 124 125 static 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 132 int 133 rsc_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 174 int 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 204 int 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 249 error: 250 kfree(mgr->rscs); 251 return err; 252 } 253 254 int 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