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 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 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                printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n");
 262                goto error;
 263        }
 264
 265        err = amixer_rsc_init(amixer, desc, mgr);
 266        if (err)
 267                goto error;
 268
 269        *ramixer = amixer;
 270
 271        return 0;
 272
 273error:
 274        spin_lock_irqsave(&mgr->mgr_lock, flags);
 275        for (i--; i >= 0; i--)
 276                mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
 277
 278        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 279        kfree(amixer);
 280        return err;
 281}
 282
 283static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer)
 284{
 285        unsigned long flags;
 286        int i;
 287
 288        spin_lock_irqsave(&mgr->mgr_lock, flags);
 289        for (i = 0; i < amixer->rsc.msr; i++)
 290                mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]);
 291
 292        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 293        amixer_rsc_uninit(amixer);
 294        kfree(amixer);
 295
 296        return 0;
 297}
 298
 299int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr)
 300{
 301        int err;
 302        struct amixer_mgr *amixer_mgr;
 303
 304        *ramixer_mgr = NULL;
 305        amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL);
 306        if (!amixer_mgr)
 307                return -ENOMEM;
 308
 309        err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw);
 310        if (err)
 311                goto error;
 312
 313        spin_lock_init(&amixer_mgr->mgr_lock);
 314
 315        amixer_mgr->get_amixer = get_amixer_rsc;
 316        amixer_mgr->put_amixer = put_amixer_rsc;
 317
 318        *ramixer_mgr = amixer_mgr;
 319
 320        return 0;
 321
 322error:
 323        kfree(amixer_mgr);
 324        return err;
 325}
 326
 327int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
 328{
 329        rsc_mgr_uninit(&amixer_mgr->mgr);
 330        kfree(amixer_mgr);
 331        return 0;
 332}
 333
 334/* SUM resource management */
 335
 336static int sum_master(struct rsc *rsc)
 337{
 338        rsc->conj = 0;
 339        return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
 340}
 341
 342static int sum_next_conj(struct rsc *rsc)
 343{
 344        rsc->conj++;
 345        return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
 346}
 347
 348static int sum_index(const struct rsc *rsc)
 349{
 350        return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
 351}
 352
 353static int sum_output_slot(const struct rsc *rsc)
 354{
 355        return (sum_index(rsc) << 4) + 0xc;
 356}
 357
 358static struct rsc_ops sum_basic_rsc_ops = {
 359        .master         = sum_master,
 360        .next_conj      = sum_next_conj,
 361        .index          = sum_index,
 362        .output_slot    = sum_output_slot,
 363};
 364
 365static int sum_rsc_init(struct sum *sum,
 366                        const struct sum_desc *desc,
 367                        struct sum_mgr *mgr)
 368{
 369        int err;
 370
 371        err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw);
 372        if (err)
 373                return err;
 374
 375        sum->rsc.ops = &sum_basic_rsc_ops;
 376
 377        return 0;
 378}
 379
 380static int sum_rsc_uninit(struct sum *sum)
 381{
 382        rsc_uninit(&sum->rsc);
 383        return 0;
 384}
 385
 386static int get_sum_rsc(struct sum_mgr *mgr,
 387                       const struct sum_desc *desc,
 388                       struct sum **rsum)
 389{
 390        int err, i;
 391        unsigned int idx;
 392        struct sum *sum;
 393        unsigned long flags;
 394
 395        *rsum = NULL;
 396
 397        /* Allocate mem for sum resource */
 398        sum = kzalloc(sizeof(*sum), GFP_KERNEL);
 399        if (!sum)
 400                return -ENOMEM;
 401
 402        /* Check whether there are sufficient sum resources to meet request. */
 403        err = 0;
 404        spin_lock_irqsave(&mgr->mgr_lock, flags);
 405        for (i = 0; i < desc->msr; i++) {
 406                err = mgr_get_resource(&mgr->mgr, 1, &idx);
 407                if (err)
 408                        break;
 409
 410                sum->idx[i] = idx;
 411        }
 412        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 413        if (err) {
 414                printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n");
 415                goto error;
 416        }
 417
 418        err = sum_rsc_init(sum, desc, mgr);
 419        if (err)
 420                goto error;
 421
 422        *rsum = sum;
 423
 424        return 0;
 425
 426error:
 427        spin_lock_irqsave(&mgr->mgr_lock, flags);
 428        for (i--; i >= 0; i--)
 429                mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
 430
 431        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 432        kfree(sum);
 433        return err;
 434}
 435
 436static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum)
 437{
 438        unsigned long flags;
 439        int i;
 440
 441        spin_lock_irqsave(&mgr->mgr_lock, flags);
 442        for (i = 0; i < sum->rsc.msr; i++)
 443                mgr_put_resource(&mgr->mgr, 1, sum->idx[i]);
 444
 445        spin_unlock_irqrestore(&mgr->mgr_lock, flags);
 446        sum_rsc_uninit(sum);
 447        kfree(sum);
 448
 449        return 0;
 450}
 451
 452int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr)
 453{
 454        int err;
 455        struct sum_mgr *sum_mgr;
 456
 457        *rsum_mgr = NULL;
 458        sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL);
 459        if (!sum_mgr)
 460                return -ENOMEM;
 461
 462        err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw);
 463        if (err)
 464                goto error;
 465
 466        spin_lock_init(&sum_mgr->mgr_lock);
 467
 468        sum_mgr->get_sum = get_sum_rsc;
 469        sum_mgr->put_sum = put_sum_rsc;
 470
 471        *rsum_mgr = sum_mgr;
 472
 473        return 0;
 474
 475error:
 476        kfree(sum_mgr);
 477        return err;
 478}
 479
 480int sum_mgr_destroy(struct sum_mgr *sum_mgr)
 481{
 482        rsc_mgr_uninit(&sum_mgr->mgr);
 483        kfree(sum_mgr);
 484        return 0;
 485}
 486
 487