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 int 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 return rsc->conj; 119 } 120 121 static int rsc_master(struct rsc *rsc) 122 { 123 return rsc->conj = rsc->idx; 124 } 125 126 static const struct rsc_ops rsc_generic_ops = { 127 .index = rsc_index, 128 .output_slot = audio_ring_slot, 129 .master = rsc_master, 130 .next_conj = rsc_next_conj, 131 }; 132 133 int 134 rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, struct hw *hw) 135 { 136 int err = 0; 137 138 rsc->idx = idx; 139 rsc->conj = idx; 140 rsc->type = type; 141 rsc->msr = msr; 142 rsc->hw = hw; 143 rsc->ops = &rsc_generic_ops; 144 if (!hw) { 145 rsc->ctrl_blk = NULL; 146 return 0; 147 } 148 149 switch (type) { 150 case SRC: 151 err = hw->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); 152 break; 153 case AMIXER: 154 err = hw->amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); 155 break; 156 case SRCIMP: 157 case SUM: 158 case DAIO: 159 break; 160 default: 161 dev_err(((struct hw *)hw)->card->dev, 162 "Invalid resource type value %d!\n", type); 163 return -EINVAL; 164 } 165 166 if (err) { 167 dev_err(((struct hw *)hw)->card->dev, 168 "Failed to get resource control block!\n"); 169 return err; 170 } 171 172 return 0; 173 } 174 175 int rsc_uninit(struct rsc *rsc) 176 { 177 if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { 178 switch (rsc->type) { 179 case SRC: 180 rsc->hw->src_rsc_put_ctrl_blk(rsc->ctrl_blk); 181 break; 182 case AMIXER: 183 rsc->hw->amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); 184 break; 185 case SUM: 186 case DAIO: 187 break; 188 default: 189 dev_err(((struct hw *)rsc->hw)->card->dev, 190 "Invalid resource type value %d!\n", 191 rsc->type); 192 break; 193 } 194 195 rsc->hw = rsc->ctrl_blk = NULL; 196 } 197 198 rsc->idx = rsc->conj = 0; 199 rsc->type = NUM_RSCTYP; 200 rsc->msr = 0; 201 202 return 0; 203 } 204 205 int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, 206 unsigned int amount, struct hw *hw) 207 { 208 int err = 0; 209 210 mgr->type = NUM_RSCTYP; 211 212 mgr->rscs = kzalloc(DIV_ROUND_UP(amount, 8), GFP_KERNEL); 213 if (!mgr->rscs) 214 return -ENOMEM; 215 216 switch (type) { 217 case SRC: 218 err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); 219 break; 220 case SRCIMP: 221 err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); 222 break; 223 case AMIXER: 224 err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); 225 break; 226 case DAIO: 227 err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); 228 break; 229 case SUM: 230 break; 231 default: 232 dev_err(hw->card->dev, 233 "Invalid resource type value %d!\n", type); 234 err = -EINVAL; 235 goto error; 236 } 237 238 if (err) { 239 dev_err(hw->card->dev, 240 "Failed to get manager control block!\n"); 241 goto error; 242 } 243 244 mgr->type = type; 245 mgr->avail = mgr->amount = amount; 246 mgr->hw = hw; 247 248 return 0; 249 250 error: 251 kfree(mgr->rscs); 252 return err; 253 } 254 255 int rsc_mgr_uninit(struct rsc_mgr *mgr) 256 { 257 kfree(mgr->rscs); 258 mgr->rscs = NULL; 259 260 if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { 261 switch (mgr->type) { 262 case SRC: 263 mgr->hw->src_mgr_put_ctrl_blk(mgr->ctrl_blk); 264 break; 265 case SRCIMP: 266 mgr->hw->srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); 267 break; 268 case AMIXER: 269 mgr->hw->amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); 270 break; 271 case DAIO: 272 mgr->hw->daio_mgr_put_ctrl_blk(mgr->ctrl_blk); 273 break; 274 case SUM: 275 break; 276 default: 277 dev_err(((struct hw *)mgr->hw)->card->dev, 278 "Invalid resource type value %d!\n", 279 mgr->type); 280 break; 281 } 282 283 mgr->hw = mgr->ctrl_blk = NULL; 284 } 285 286 mgr->type = NUM_RSCTYP; 287 mgr->avail = mgr->amount = 0; 288 289 return 0; 290 } 291