linux/sound/pci/ctxfi/ctresource.c
<<
>>
Prefs
   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 */
  22static int
  23get_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 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 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
 121static int rsc_master(struct rsc *rsc)
 122{
 123        return rsc->conj = rsc->idx;
 124}
 125
 126static 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
 133int
 134rsc_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
 175int 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
 205int 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(((amount + 8 - 1) / 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
 250error:
 251        kfree(mgr->rscs);
 252        return err;
 253}
 254
 255int 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