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