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 30 static 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 36 static int amixer_next_conj(struct rsc *rsc) 37 { 38 rsc->conj++; 39 return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; 40 } 41 42 static int amixer_index(const struct rsc *rsc) 43 { 44 return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; 45 } 46 47 static int amixer_output_slot(const struct rsc *rsc) 48 { 49 return (amixer_index(rsc) << 4) + 0x4; 50 } 51 52 static 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 59 static 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 */ 76 static 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 86 static 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 96 static 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 113 static 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 159 static 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 171 static 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 179 static 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 189 static 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 200 static 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 222 static 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 232 static 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 273 error: 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 283 static 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 299 int 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 322 error: 323 kfree(amixer_mgr); 324 return err; 325 } 326 327 int 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 336 static 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 342 static int sum_next_conj(struct rsc *rsc) 343 { 344 rsc->conj++; 345 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 346 } 347 348 static int sum_index(const struct rsc *rsc) 349 { 350 return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; 351 } 352 353 static int sum_output_slot(const struct rsc *rsc) 354 { 355 return (sum_index(rsc) << 4) + 0xc; 356 } 357 358 static 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 365 static 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 380 static int sum_rsc_uninit(struct sum *sum) 381 { 382 rsc_uninit(&sum->rsc); 383 return 0; 384 } 385 386 static 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 426 error: 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 436 static 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 452 int 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 475 error: 476 kfree(sum_mgr); 477 return err; 478 } 479 480 int 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