linux/sound/pci/ctxfi/ctamixer.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        ctamixer.c
   9 *
  10 * @Brief
  11 * This file contains the implementation of the Audio Mixer
  12 * resource management object.
  13 *
  14 * @Author      Liu Chun
  15 * @Date        May 21 2008
  16 *
  17 */
  18
  19#include "ctamixer.h"
  20#include "cthardware.h"
  21#include <linux/slab.h>
  22
  23#define AMIXER_RESOURCE_NUM     256
  24#define SUM_RESOURCE_NUM        256
  25
  26#define AMIXER_Y_IMMEDIATE      1
  27
  28#define BLANK_SLOT              4094
  29
  30static int amixer_master(struct rsc *rsc)
  31{
  32        rsc->conj = 0;
  33        return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
  34}
  35
  36static int amixer_next_conj(struct rsc *rsc)
  37{
  38        rsc->conj++;
  39        return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
  40}
  41
  42static int amixer_index(const struct rsc *rsc)
  43{
  44        return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
  45}
  46
  47static int amixer_output_slot(const struct rsc *rsc)
  48{
  49        return (amixer_index(rsc) << 4) + 0x4;
  50}
  51
  52static const struct rsc_ops amixer_basic_rsc_ops = {
  53        .master         = amixer_master,
  54        .next_conj      = amixer_next_conj,
  55        .index          = amixer_index,
  56        .output_slot    = amixer_output_slot,
  57};
  58
  59static int amixer_set_input(struct amixer *amixer, struct rsc *rsc)
  60{
  61        struct hw *hw;
  62
  63        hw = amixer->rsc.hw;
  64        hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE);
  65        amixer->input = rsc;
  66        if (!rsc)
  67                hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT);
  68        else
  69                hw->amixer_set_x(amixer->rsc.ctrl_blk,
  70                                        rsc->ops->output_slot(rsc));
  71
  72        return 0;
  73}
  74
  75/* y is a 14-bit immediate constant */
  76static int amixer_set_y(struct amixer *amixer, unsigned int y)
  77{
  78        struct hw *hw;
  79
  80        hw = amixer->rsc.hw;
  81        hw->amixer_set_y(amixer->rsc.ctrl_blk, y);
  82
  83        return 0;
  84}
  85
  86static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv)
  87{
  88        struct hw *hw;
  89
  90        hw = amixer->rsc.hw;
  91        hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv);
  92
  93        return 0;
  94}
  95
  96static int amixer_set_sum(struct amixer *amixer, struct sum *sum)
  97{
  98        struct hw *hw;
  99
 100        hw = amixer->rsc.hw;
 101        amixer->sum = sum;
 102        if (!sum) {
 103                hw->amixer_set_se(amixer->rsc.ctrl_blk, 0);
 104        } else {
 105                hw->amixer_set_se(amixer->rsc.ctrl_blk, 1);
 106                hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
 107                                        sum->rsc.ops->index(&sum->rsc));
 108        }
 109
 110        return 0;
 111}
 112
 113static int amixer_commit_write(struct amixer *amixer)
 114{
 115        struct hw *hw;
 116        unsigned int index;
 117        int i;
 118        struct rsc *input;
 119        struct sum *sum;
 120
 121        hw = amixer->rsc.hw;
 122        input = amixer->input;
 123        sum = amixer->sum;
 124
 125        /* Program master and conjugate resources */
 126        amixer->rsc.ops->master(&amixer->rsc);
 127        if (input)
 128                input->ops->master(input);
 129
 130        if (sum)
 131                sum->rsc.ops->master(&sum->rsc);
 132
 133        for (i = 0; i < amixer->rsc.msr; i++) {
 134                hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk);
 135                if (input) {
 136                        hw->amixer_set_x(amixer->rsc.ctrl_blk,
 137                                                input->ops->output_slot(input));
 138                        input->ops->next_conj(input);
 139                }
 140                if (sum) {
 141                        hw->amixer_set_sadr(amixer->rsc.ctrl_blk,
 142                                                sum->rsc.ops->index(&sum->rsc));
 143                        sum->rsc.ops->next_conj(&sum->rsc);
 144                }
 145                index = amixer->rsc.ops->output_slot(&amixer->rsc);
 146                hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
 147                amixer->rsc.ops->next_conj(&amixer->rsc);
 148        }
 149        amixer->rsc.ops->master(&amixer->rsc);
 150        if (input)
 151                input->ops->master(input);
 152
 153        if (sum)
 154                sum->rsc.ops->master(&sum->rsc);
 155
 156        return 0;
 157}
 158
 159static int amixer_commit_raw_write(struct amixer *amixer)
 160{
 161        struct hw *hw;
 162        unsigned int index;
 163
 164        hw = amixer->rsc.hw;
 165        index = amixer->rsc.ops->output_slot(&amixer->rsc);
 166        hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk);
 167
 168        return 0;
 169}
 170
 171static int amixer_get_y(struct amixer *amixer)
 172{
 173        struct hw *hw;
 174
 175        hw = amixer->rsc.hw;
 176        return hw->amixer_get_y(amixer->rsc.ctrl_blk);
 177}
 178
 179static int amixer_setup(struct amixer *amixer, struct rsc *input,
 180                        unsigned int scale, struct sum *sum)
 181{
 182        amixer_set_input(amixer, input);
 183        amixer_set_y(amixer, scale);
 184        amixer_set_sum(amixer, sum);
 185        amixer_commit_write(amixer);
 186        return 0;
 187}
 188
 189static const struct amixer_rsc_ops amixer_ops = {
 190        .set_input              = amixer_set_input,
 191        .set_invalid_squash     = amixer_set_invalid_squash,
 192        .set_scale              = amixer_set_y,
 193        .set_sum                = amixer_set_sum,
 194        .commit_write           = amixer_commit_write,
 195        .commit_raw_write       = amixer_commit_raw_write,
 196        .setup                  = amixer_setup,
 197        .get_scale              = amixer_get_y,
 198};
 199
 200static int amixer_rsc_init(struct amixer *amixer,
 201                           const struct amixer_desc *desc,
 202                           struct amixer_mgr *mgr)
 203{
 204        int err;
 205
 206        err = rsc_init(&amixer->rsc, amixer->idx[0],
 207                        AMIXER, desc->msr, mgr->mgr.hw);
 208        if (err)
 209                return err;
 210
 211        /* Set amixer specific operations */
 212        amixer->rsc.ops = &amixer_basic_rsc_ops;
 213        amixer->ops = &amixer_ops;
 214        amixer->input = NULL;
 215        amixer->sum = NULL;
 216
 217        amixer_setup(amixer, NULL, 0, NULL);
 218
 219        return 0;
 220}
 221
 222static int amixer_rsc_uninit(struct amixer *amixer)
 223{
 224        amixer_setup(amixer, NULL, 0, NULL);
 225        rsc_uninit(&amixer->rsc);
 226        amixer->ops = NULL;
 227        amixer->input = NULL;
 228        amixer->sum = NULL;
 229        return 0;
 230}
 231
 232static int get_amixer_rsc(struct amixer_mgr *mgr,
 233                          const struct amixer_desc *desc,
 234                          struct amixer **ramixer)
 235{
 236        int err, i;
 237        unsigned int idx;
 238        struct amixer *amixer;
 239        unsigned long flags;
 240
 241        *ramixer = NULL;
 242
 243        /* Allocate mem for amixer resource */
 244        amixer = kzalloc(sizeof(*amixer), GFP_KERNEL);
 245        if (!amixer)
 246                return -ENOMEM;
 247
 248        /* Check whether there are sufficient
 249         * amixer resources to meet request. */
 250        err = 0;
 251        spin_lock_irqsave(&mgr->mgr_lock, flags);
 252        for (i = 0; i < desc->msr; i++) {
 253                err = mgr_get_resource(&mgr->mgr, 1, &idx);
 254                if (err)
 255                        break;
 256
 257                amixer->idx[i] = idx;
 258        }
 259        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 260        if (err) {
 261                dev_err(mgr->card->dev,
 262                        "Can't meet AMIXER resource request!\n");
 263                goto error;
 264        }
 265
 266        err = amixer_rsc_init(amixer, desc, mgr);
 267        if (err)
 268                goto error;
 269
 270        *ramixer = amixer;
 271
 272        return 0;
 273
 274error:
 275        spin_lock_irqsave(&mgr->mgr_lock, flags);
 276        for (i--; i >= 0; i--)
 277                mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
 278
 279        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 280        kfree(amixer);
 281        return err;
 282}
 283
 284static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
 285{
 286        unsigned long flags;
 287        int i;
 288
 289        spin_lock_irqsave(&mgr->mgr_lock, flags);
 290        for (i = 0; i < amixer->rsc.msr; i++)
 291                mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
 292
 293        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 294        amixer_rsc_uninit(amixer);
 295        kfree(amixer);
 296
 297        return 0;
 298}
 299
 300int amixer_mgr_create(struct hw *hw, struct amixer_mgr **ramixer_mgr)
 301{
 302        int err;
 303        struct amixer_mgr *amixer_mgr;
 304
 305        *ramixer_mgr = NULL;
 306        amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
 307        if (!amixer_mgr)
 308                return -ENOMEM;
 309
 310        err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
 311        if (err)
 312                goto error;
 313
 314        spin_lock_init(&amixer_mgr->mgr_lock);
 315
 316        amixer_mgr->get_amixer = get_amixer_rsc;
 317        amixer_mgr->put_amixer = put_amixer_rsc;
 318        amixer_mgr->card = hw->card;
 319
 320        *ramixer_mgr = amixer_mgr;
 321
 322        return 0;
 323
 324error:
 325        kfree(amixer_mgr);
 326        return err;
 327}
 328
 329int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
 330{
 331        rsc_mgr_uninit(&amixer_mgr->mgr);
 332        kfree(amixer_mgr);
 333        return 0;
 334}
 335
 336/* SUM resource management */
 337
 338static int sum_master(struct rsc *rsc)
 339{
 340        rsc->conj = 0;
 341        return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
 342}
 343
 344static int sum_next_conj(struct rsc *rsc)
 345{
 346        rsc->conj++;
 347        return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
 348}
 349
 350static int sum_index(const struct rsc *rsc)
 351{
 352        return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
 353}
 354
 355static int sum_output_slot(const struct rsc *rsc)
 356{
 357        return (sum_index(rsc) << 4) + 0xc;
 358}
 359
 360static const struct rsc_ops sum_basic_rsc_ops = {
 361        .master         = sum_master,
 362        .next_conj      = sum_next_conj,
 363        .index          = sum_index,
 364        .output_slot    = sum_output_slot,
 365};
 366
 367static int sum_rsc_init(struct sum *sum,
 368                        const struct sum_desc *desc,
 369                        struct sum_mgr *mgr)
 370{
 371        int err;
 372
 373        err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
 374        if (err)
 375                return err;
 376
 377        sum->rsc.ops = &sum_basic_rsc_ops;
 378
 379        return 0;
 380}
 381
 382static int sum_rsc_uninit(struct sum *sum)
 383{
 384        rsc_uninit(&sum->rsc);
 385        return 0;
 386}
 387
 388static int get_sum_rsc(struct sum_mgr *mgr,
 389                       const struct sum_desc *desc,
 390                       struct sum **rsum)
 391{
 392        int err, i;
 393        unsigned int idx;
 394        struct sum *sum;
 395        unsigned long flags;
 396
 397        *rsum = NULL;
 398
 399        /* Allocate mem for sum resource */
 400        sum = kzalloc(sizeof(*sum), GFP_KERNEL);
 401        if (!sum)
 402                return -ENOMEM;
 403
 404        /* Check whether there are sufficient sum resources to meet request. */
 405        err = 0;
 406        spin_lock_irqsave(&mgr->mgr_lock, flags);
 407        for (i = 0; i < desc->msr; i++) {
 408                err = mgr_get_resource(&mgr->mgr, 1, &idx);
 409                if (err)
 410                        break;
 411
 412                sum->idx[i] = idx;
 413        }
 414        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 415        if (err) {
 416                dev_err(mgr->card->dev,
 417                        "Can't meet SUM resource request!\n");
 418                goto error;
 419        }
 420
 421        err = sum_rsc_init(sum, desc, mgr);
 422        if (err)
 423                goto error;
 424
 425        *rsum = sum;
 426
 427        return 0;
 428
 429error:
 430        spin_lock_irqsave(&mgr->mgr_lock, flags);
 431        for (i--; i >= 0; i--)
 432                mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
 433
 434        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 435        kfree(sum);
 436        return err;
 437}
 438
 439static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
 440{
 441        unsigned long flags;
 442        int i;
 443
 444        spin_lock_irqsave(&mgr->mgr_lock, flags);
 445        for (i = 0; i < sum->rsc.msr; i++)
 446                mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
 447
 448        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 449        sum_rsc_uninit(sum);
 450        kfree(sum);
 451
 452        return 0;
 453}
 454
 455int sum_mgr_create(struct hw *hw, struct sum_mgr **rsum_mgr)
 456{
 457        int err;
 458        struct sum_mgr *sum_mgr;
 459
 460        *rsum_mgr = NULL;
 461        sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
 462        if (!sum_mgr)
 463                return -ENOMEM;
 464
 465        err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
 466        if (err)
 467                goto error;
 468
 469        spin_lock_init(&sum_mgr->mgr_lock);
 470
 471        sum_mgr->get_sum = get_sum_rsc;
 472        sum_mgr->put_sum = put_sum_rsc;
 473        sum_mgr->card = hw->card;
 474
 475        *rsum_mgr = sum_mgr;
 476
 477        return 0;
 478
 479error:
 480        kfree(sum_mgr);
 481        return err;
 482}
 483
 484int sum_mgr_destroy(struct sum_mgr *sum_mgr)
 485{
 486        rsc_mgr_uninit(&sum_mgr->mgr);
 487        kfree(sum_mgr);
 488        return 0;
 489}
 490
 491