diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-11-15 10:05:26 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:24 -0500 |
commit | 9c45ba100501c206658f356ea1db3263947b9a30 (patch) | |
tree | aabc0618c67c410844b30c90e21dc8d78dce4f4a /sound | |
parent | 4e98d6a7ce934b19bffb309f2522b22384355fef (diff) |
[ALSA] ice1724 - Clean up ctl callbacks in se.c
Clean up ctl callbacks of SE-200PCI driver. Also make sure to check
the value ranges.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/ice1712/se.c | 238 |
1 files changed, 147 insertions, 91 deletions
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c index ebfe2454a08b..3c8b518118e9 100644 --- a/sound/pci/ice1712/se.c +++ b/sound/pci/ice1712/se.c | |||
@@ -415,134 +415,177 @@ static const struct se200pci_control se200pci_cont[] = { | |||
415 | } | 415 | } |
416 | }; | 416 | }; |
417 | 417 | ||
418 | static int se200pci_cont_info(struct snd_kcontrol *kc, | 418 | static int se200pci_get_enum_count(int n) |
419 | struct snd_ctl_elem_info *uinfo) | ||
420 | { | 419 | { |
421 | struct snd_ice1712 *ice; | ||
422 | int n; | ||
423 | int c; | ||
424 | const char **member; | 420 | const char **member; |
421 | int c; | ||
425 | 422 | ||
426 | ice = snd_kcontrol_chip(kc); | 423 | member = se200pci_cont[n].member; |
427 | n = kc->private_value; | 424 | if (!member) |
428 | 425 | return 0; | |
429 | if (se200pci_cont[n].type == VOLUME1 || | 426 | for (c = 0; member[c]; c++) |
430 | se200pci_cont[n].type == VOLUME2) { | 427 | ; |
431 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 428 | return c; |
432 | uinfo->count = 2; | 429 | } |
433 | uinfo->value.integer.min = 0; /* mute */ | ||
434 | uinfo->value.integer.max = 0xff; /* 0dB */ | ||
435 | |||
436 | } else if (se200pci_cont[n].type == BOOLEAN) { | ||
437 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
438 | uinfo->count = 1; | ||
439 | uinfo->value.integer.min = 0; | ||
440 | uinfo->value.integer.max = 1; | ||
441 | |||
442 | } else if (se200pci_cont[n].type == ENUM) { | ||
443 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
444 | member = se200pci_cont[n].member; | ||
445 | if (member == NULL) | ||
446 | return -EINVAL; | ||
447 | for (c = 0; member[c]; c++) | ||
448 | ; | ||
449 | |||
450 | uinfo->count = 1; | ||
451 | uinfo->value.enumerated.items = c; | ||
452 | if (uinfo->value.enumerated.item >= c) | ||
453 | uinfo->value.enumerated.item = c - 1; | ||
454 | strcpy(uinfo->value.enumerated.name, | ||
455 | member[uinfo->value.enumerated.item]); | ||
456 | } | ||
457 | 430 | ||
431 | static int se200pci_cont_volume_info(struct snd_kcontrol *kc, | ||
432 | struct snd_ctl_elem_info *uinfo) | ||
433 | { | ||
434 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
435 | uinfo->count = 2; | ||
436 | uinfo->value.integer.min = 0; /* mute */ | ||
437 | uinfo->value.integer.max = 0xff; /* 0dB */ | ||
458 | return 0; | 438 | return 0; |
459 | } | 439 | } |
460 | 440 | ||
461 | static int se200pci_cont_get(struct snd_kcontrol *kc, | 441 | #define se200pci_cont_boolean_info snd_ctl_boolean_mono_info |
462 | struct snd_ctl_elem_value *uc) | 442 | |
443 | static int se200pci_cont_enum_info(struct snd_kcontrol *kc, | ||
444 | struct snd_ctl_elem_info *uinfo) | ||
463 | { | 445 | { |
464 | struct snd_ice1712 *ice; | 446 | int n, c; |
465 | int n; | ||
466 | 447 | ||
467 | ice = snd_kcontrol_chip(kc); | ||
468 | n = kc->private_value; | 448 | n = kc->private_value; |
469 | if (se200pci_cont[n].type == VOLUME1 || | 449 | c = se200pci_get_enum_count(n); |
470 | se200pci_cont[n].type == VOLUME2) { | 450 | if (!c) |
471 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; | 451 | return -EINVAL; |
472 | uc->value.integer.value[1] = ice->spec.se.vol[n].ch2; | 452 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
473 | 453 | uinfo->count = 1; | |
474 | } else if (se200pci_cont[n].type == BOOLEAN || | 454 | uinfo->value.enumerated.items = c; |
475 | se200pci_cont[n].type == ENUM) | 455 | if (uinfo->value.enumerated.item >= c) |
476 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; | 456 | uinfo->value.enumerated.item = c - 1; |
477 | 457 | strcpy(uinfo->value.enumerated.name, | |
458 | se200pci_cont[n].member[uinfo->value.enumerated.item]); | ||
478 | return 0; | 459 | return 0; |
479 | } | 460 | } |
480 | 461 | ||
481 | static int se200pci_cont_put(struct snd_kcontrol *kc, | 462 | static int se200pci_cont_volume_get(struct snd_kcontrol *kc, |
482 | struct snd_ctl_elem_value *uc) | 463 | struct snd_ctl_elem_value *uc) |
483 | { | 464 | { |
484 | struct snd_ice1712 *ice; | 465 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); |
485 | int n; | 466 | int n = kc->private_value; |
486 | unsigned int vol1, vol2; | 467 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; |
487 | int changed; | 468 | uc->value.integer.value[1] = ice->spec.se.vol[n].ch2; |
488 | 469 | return 0; | |
489 | ice = snd_kcontrol_chip(kc); | 470 | } |
490 | n = kc->private_value; | ||
491 | 471 | ||
492 | changed = 0; | 472 | static int se200pci_cont_boolean_get(struct snd_kcontrol *kc, |
493 | vol1 = 0; vol2 = 0; | 473 | struct snd_ctl_elem_value *uc) |
494 | if (se200pci_cont[n].type == VOLUME1 || | 474 | { |
495 | se200pci_cont[n].type == VOLUME2) { | 475 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); |
496 | vol1 = uc->value.integer.value[0]; | 476 | int n = kc->private_value; |
497 | vol2 = uc->value.integer.value[1]; | 477 | uc->value.integer.value[0] = ice->spec.se.vol[n].ch1; |
498 | if (ice->spec.se.vol[n].ch1 != vol1) | 478 | return 0; |
499 | changed = 1; | 479 | } |
500 | if (ice->spec.se.vol[n].ch2 != vol2) | ||
501 | changed = 1; | ||
502 | ice->spec.se.vol[n].ch1 = vol1; | ||
503 | ice->spec.se.vol[n].ch2 = vol2; | ||
504 | 480 | ||
505 | } else if (se200pci_cont[n].type == BOOLEAN || | 481 | static int se200pci_cont_enum_get(struct snd_kcontrol *kc, |
506 | se200pci_cont[n].type == ENUM) { | 482 | struct snd_ctl_elem_value *uc) |
507 | vol1 = uc->value.integer.value[0]; | 483 | { |
508 | if (ice->spec.se.vol[n].ch1 != vol1) | 484 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); |
509 | changed = 1; | 485 | int n = kc->private_value; |
510 | ice->spec.se.vol[n].ch1 = vol1; | 486 | uc->value.enumerated.item[0] = ice->spec.se.vol[n].ch1; |
511 | } | 487 | return 0; |
488 | } | ||
512 | 489 | ||
490 | static void se200pci_cont_update(struct snd_ice1712 *ice, int n) | ||
491 | { | ||
513 | switch (se200pci_cont[n].target) { | 492 | switch (se200pci_cont[n].target) { |
514 | case WM8766: | 493 | case WM8766: |
515 | se200pci_WM8766_set_volume(ice, | 494 | se200pci_WM8766_set_volume(ice, |
516 | se200pci_cont[n].ch, vol1, vol2); | 495 | se200pci_cont[n].ch, |
496 | ice->spec.se.vol[n].ch1, | ||
497 | ice->spec.se.vol[n].ch2); | ||
517 | break; | 498 | break; |
518 | 499 | ||
519 | case WM8776in: | 500 | case WM8776in: |
520 | se200pci_WM8776_set_input_volume(ice, vol1, vol2); | 501 | se200pci_WM8776_set_input_volume(ice, |
502 | ice->spec.se.vol[n].ch1, | ||
503 | ice->spec.se.vol[n].ch2); | ||
521 | break; | 504 | break; |
522 | 505 | ||
523 | case WM8776out: | 506 | case WM8776out: |
524 | se200pci_WM8776_set_output_volume(ice, vol1, vol2); | 507 | se200pci_WM8776_set_output_volume(ice, |
508 | ice->spec.se.vol[n].ch1, | ||
509 | ice->spec.se.vol[n].ch2); | ||
525 | break; | 510 | break; |
526 | 511 | ||
527 | case WM8776sel: | 512 | case WM8776sel: |
528 | se200pci_WM8776_set_input_selector(ice, vol1); | 513 | se200pci_WM8776_set_input_selector(ice, |
514 | ice->spec.se.vol[n].ch1); | ||
529 | break; | 515 | break; |
530 | 516 | ||
531 | case WM8776agc: | 517 | case WM8776agc: |
532 | se200pci_WM8776_set_agc(ice, vol1); | 518 | se200pci_WM8776_set_agc(ice, ice->spec.se.vol[n].ch1); |
533 | break; | 519 | break; |
534 | 520 | ||
535 | case WM8776afl: | 521 | case WM8776afl: |
536 | se200pci_WM8776_set_afl(ice, vol1); | 522 | se200pci_WM8776_set_afl(ice, ice->spec.se.vol[n].ch1); |
537 | break; | 523 | break; |
538 | 524 | ||
539 | default: | 525 | default: |
540 | break; | 526 | break; |
541 | } | 527 | } |
528 | } | ||
529 | |||
530 | static int se200pci_cont_volume_put(struct snd_kcontrol *kc, | ||
531 | struct snd_ctl_elem_value *uc) | ||
532 | { | ||
533 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
534 | int n = kc->private_value; | ||
535 | unsigned int vol1, vol2; | ||
536 | int changed; | ||
537 | |||
538 | changed = 0; | ||
539 | vol1 = uc->value.integer.value[0] & 0xff; | ||
540 | vol2 = uc->value.integer.value[1] & 0xff; | ||
541 | if (ice->spec.se.vol[n].ch1 != vol1) { | ||
542 | ice->spec.se.vol[n].ch1 = vol1; | ||
543 | changed = 1; | ||
544 | } | ||
545 | if (ice->spec.se.vol[n].ch2 != vol2) { | ||
546 | ice->spec.se.vol[n].ch2 = vol2; | ||
547 | changed = 1; | ||
548 | } | ||
549 | if (changed) | ||
550 | se200pci_cont_update(ice, n); | ||
542 | 551 | ||
543 | return changed; | 552 | return changed; |
544 | } | 553 | } |
545 | 554 | ||
555 | static int se200pci_cont_boolean_put(struct snd_kcontrol *kc, | ||
556 | struct snd_ctl_elem_value *uc) | ||
557 | { | ||
558 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
559 | int n = kc->private_value; | ||
560 | unsigned int vol1; | ||
561 | |||
562 | vol1 = !!uc->value.integer.value[0]; | ||
563 | if (ice->spec.se.vol[n].ch1 != vol1) { | ||
564 | ice->spec.se.vol[n].ch1 = vol1; | ||
565 | se200pci_cont_update(ice, n); | ||
566 | return 1; | ||
567 | } | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int se200pci_cont_enum_put(struct snd_kcontrol *kc, | ||
572 | struct snd_ctl_elem_value *uc) | ||
573 | { | ||
574 | struct snd_ice1712 *ice = snd_kcontrol_chip(kc); | ||
575 | int n = kc->private_value; | ||
576 | unsigned int vol1; | ||
577 | |||
578 | vol1 = uc->value.enumerated.item[0]; | ||
579 | if (vol1 >= se200pci_get_enum_count(n)) | ||
580 | return -EINVAL; | ||
581 | if (ice->spec.se.vol[n].ch1 != vol1) { | ||
582 | ice->spec.se.vol[n].ch1 = vol1; | ||
583 | se200pci_cont_update(ice, n); | ||
584 | return 1; | ||
585 | } | ||
586 | return 0; | ||
587 | } | ||
588 | |||
546 | static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); | 589 | static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); |
547 | static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); | 590 | static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); |
548 | 591 | ||
@@ -554,23 +597,36 @@ static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) | |||
554 | 597 | ||
555 | memset(&cont, 0, sizeof(cont)); | 598 | memset(&cont, 0, sizeof(cont)); |
556 | cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 599 | cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
557 | cont.info = se200pci_cont_info; | ||
558 | cont.get = se200pci_cont_get; | ||
559 | cont.put = se200pci_cont_put; | ||
560 | for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) { | 600 | for (i = 0; i < ARRAY_SIZE(se200pci_cont); i++) { |
561 | cont.private_value = i; | 601 | cont.private_value = i; |
562 | cont.name = se200pci_cont[i].name; | 602 | cont.name = se200pci_cont[i].name; |
563 | cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | 603 | cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; |
564 | cont.tlv.p = NULL; | 604 | cont.tlv.p = NULL; |
565 | if (se200pci_cont[i].type == VOLUME1 || | 605 | switch (se200pci_cont[i].type) { |
566 | se200pci_cont[i].type == VOLUME2) { | 606 | case VOLUME1: |
567 | 607 | case VOLUME2: | |
608 | cont.info = se200pci_cont_volume_info; | ||
609 | cont.get = se200pci_cont_volume_get; | ||
610 | cont.put = se200pci_cont_volume_put; | ||
568 | cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | 611 | cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
569 | |||
570 | if (se200pci_cont[i].type == VOLUME1) | 612 | if (se200pci_cont[i].type == VOLUME1) |
571 | cont.tlv.p = db_scale_gain1; | 613 | cont.tlv.p = db_scale_gain1; |
572 | else | 614 | else |
573 | cont.tlv.p = db_scale_gain2; | 615 | cont.tlv.p = db_scale_gain2; |
616 | break; | ||
617 | case BOOLEAN: | ||
618 | cont.info = se200pci_cont_boolean_info; | ||
619 | cont.get = se200pci_cont_boolean_get; | ||
620 | cont.put = se200pci_cont_boolean_put; | ||
621 | break; | ||
622 | case ENUM: | ||
623 | cont.info = se200pci_cont_enum_info; | ||
624 | cont.get = se200pci_cont_enum_get; | ||
625 | cont.put = se200pci_cont_enum_put; | ||
626 | break; | ||
627 | default: | ||
628 | snd_BUG(); | ||
629 | return -EINVAL; | ||
574 | } | 630 | } |
575 | err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice)); | 631 | err = snd_ctl_add(ice->card, snd_ctl_new1(&cont, ice)); |
576 | if (err < 0) | 632 | if (err < 0) |