root/sound/pci/ctxfi/ctmixer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_amixer_index
  2. get_recording_amixer
  3. get_switch_state
  4. set_switch_state
  5. uint16_to_float14
  6. float14_to_uint16
  7. ct_alsa_mix_volume_info
  8. ct_alsa_mix_volume_get
  9. ct_alsa_mix_volume_put
  10. output_switch_info
  11. output_switch_get
  12. output_switch_put
  13. mic_source_switch_info
  14. mic_source_switch_get
  15. mic_source_switch_put
  16. do_line_mic_switch
  17. do_digit_io_switch
  18. do_switch
  19. ct_alsa_mix_switch_info
  20. ct_alsa_mix_switch_get
  21. ct_alsa_mix_switch_put
  22. ct_spdif_info
  23. ct_spdif_get_mask
  24. ct_spdif_get
  25. ct_spdif_put
  26. ct_mixer_kcontrol_new
  27. ct_mixer_kcontrols_create
  28. ct_mixer_recording_select
  29. ct_mixer_recording_unselect
  30. ct_mixer_get_resources
  31. ct_mixer_get_mem
  32. ct_mixer_topology_build
  33. mixer_set_input_port
  34. port_to_amixer
  35. mixer_get_output_ports
  36. mixer_set_input_left
  37. mixer_set_input_right
  38. mixer_resume
  39. ct_mixer_destroy
  40. ct_mixer_create
  41. ct_alsa_mix_create

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /**
   3  * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
   4  *
   5  * @File        ctmixer.c
   6  *
   7  * @Brief
   8  * This file contains the implementation of alsa mixer device functions.
   9  *
  10  * @Author      Liu Chun
  11  * @Date        May 28 2008
  12  */
  13 
  14 
  15 #include "ctmixer.h"
  16 #include "ctamixer.h"
  17 #include <linux/slab.h>
  18 #include <sound/core.h>
  19 #include <sound/control.h>
  20 #include <sound/asoundef.h>
  21 #include <sound/pcm.h>
  22 #include <sound/tlv.h>
  23 
  24 enum CT_SUM_CTL {
  25         SUM_IN_F,
  26         SUM_IN_R,
  27         SUM_IN_C,
  28         SUM_IN_S,
  29         SUM_IN_F_C,
  30 
  31         NUM_CT_SUMS
  32 };
  33 
  34 enum CT_AMIXER_CTL {
  35         /* volume control mixers */
  36         AMIXER_MASTER_F,
  37         AMIXER_MASTER_R,
  38         AMIXER_MASTER_C,
  39         AMIXER_MASTER_S,
  40         AMIXER_PCM_F,
  41         AMIXER_PCM_R,
  42         AMIXER_PCM_C,
  43         AMIXER_PCM_S,
  44         AMIXER_SPDIFI,
  45         AMIXER_LINEIN,
  46         AMIXER_MIC,
  47         AMIXER_SPDIFO,
  48         AMIXER_WAVE_F,
  49         AMIXER_WAVE_R,
  50         AMIXER_WAVE_C,
  51         AMIXER_WAVE_S,
  52         AMIXER_MASTER_F_C,
  53         AMIXER_PCM_F_C,
  54         AMIXER_SPDIFI_C,
  55         AMIXER_LINEIN_C,
  56         AMIXER_MIC_C,
  57 
  58         /* this should always be the last one */
  59         NUM_CT_AMIXERS
  60 };
  61 
  62 enum CTALSA_MIXER_CTL {
  63         /* volume control mixers */
  64         MIXER_MASTER_P,
  65         MIXER_PCM_P,
  66         MIXER_LINEIN_P,
  67         MIXER_MIC_P,
  68         MIXER_SPDIFI_P,
  69         MIXER_SPDIFO_P,
  70         MIXER_WAVEF_P,
  71         MIXER_WAVER_P,
  72         MIXER_WAVEC_P,
  73         MIXER_WAVES_P,
  74         MIXER_MASTER_C,
  75         MIXER_PCM_C,
  76         MIXER_LINEIN_C,
  77         MIXER_MIC_C,
  78         MIXER_SPDIFI_C,
  79 
  80         /* switch control mixers */
  81         MIXER_PCM_C_S,
  82         MIXER_LINEIN_C_S,
  83         MIXER_MIC_C_S,
  84         MIXER_SPDIFI_C_S,
  85         MIXER_SPDIFO_P_S,
  86         MIXER_WAVEF_P_S,
  87         MIXER_WAVER_P_S,
  88         MIXER_WAVEC_P_S,
  89         MIXER_WAVES_P_S,
  90         MIXER_DIGITAL_IO_S,
  91         MIXER_IEC958_MASK,
  92         MIXER_IEC958_DEFAULT,
  93         MIXER_IEC958_STREAM,
  94 
  95         /* this should always be the last one */
  96         NUM_CTALSA_MIXERS
  97 };
  98 
  99 #define VOL_MIXER_START         MIXER_MASTER_P
 100 #define VOL_MIXER_END           MIXER_SPDIFI_C
 101 #define VOL_MIXER_NUM           (VOL_MIXER_END - VOL_MIXER_START + 1)
 102 #define SWH_MIXER_START         MIXER_PCM_C_S
 103 #define SWH_MIXER_END           MIXER_DIGITAL_IO_S
 104 #define SWH_CAPTURE_START       MIXER_PCM_C_S
 105 #define SWH_CAPTURE_END         MIXER_SPDIFI_C_S
 106 
 107 #define CHN_NUM         2
 108 
 109 struct ct_kcontrol_init {
 110         unsigned char ctl;
 111         char *name;
 112 };
 113 
 114 static struct ct_kcontrol_init
 115 ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = {
 116         [MIXER_MASTER_P] = {
 117                 .ctl = 1,
 118                 .name = "Master Playback Volume",
 119         },
 120         [MIXER_MASTER_C] = {
 121                 .ctl = 1,
 122                 .name = "Master Capture Volume",
 123         },
 124         [MIXER_PCM_P] = {
 125                 .ctl = 1,
 126                 .name = "PCM Playback Volume",
 127         },
 128         [MIXER_PCM_C] = {
 129                 .ctl = 1,
 130                 .name = "PCM Capture Volume",
 131         },
 132         [MIXER_LINEIN_P] = {
 133                 .ctl = 1,
 134                 .name = "Line Playback Volume",
 135         },
 136         [MIXER_LINEIN_C] = {
 137                 .ctl = 1,
 138                 .name = "Line Capture Volume",
 139         },
 140         [MIXER_MIC_P] = {
 141                 .ctl = 1,
 142                 .name = "Mic Playback Volume",
 143         },
 144         [MIXER_MIC_C] = {
 145                 .ctl = 1,
 146                 .name = "Mic Capture Volume",
 147         },
 148         [MIXER_SPDIFI_P] = {
 149                 .ctl = 1,
 150                 .name = "IEC958 Playback Volume",
 151         },
 152         [MIXER_SPDIFI_C] = {
 153                 .ctl = 1,
 154                 .name = "IEC958 Capture Volume",
 155         },
 156         [MIXER_SPDIFO_P] = {
 157                 .ctl = 1,
 158                 .name = "Digital Playback Volume",
 159         },
 160         [MIXER_WAVEF_P] = {
 161                 .ctl = 1,
 162                 .name = "Front Playback Volume",
 163         },
 164         [MIXER_WAVES_P] = {
 165                 .ctl = 1,
 166                 .name = "Side Playback Volume",
 167         },
 168         [MIXER_WAVEC_P] = {
 169                 .ctl = 1,
 170                 .name = "Center/LFE Playback Volume",
 171         },
 172         [MIXER_WAVER_P] = {
 173                 .ctl = 1,
 174                 .name = "Surround Playback Volume",
 175         },
 176         [MIXER_PCM_C_S] = {
 177                 .ctl = 1,
 178                 .name = "PCM Capture Switch",
 179         },
 180         [MIXER_LINEIN_C_S] = {
 181                 .ctl = 1,
 182                 .name = "Line Capture Switch",
 183         },
 184         [MIXER_MIC_C_S] = {
 185                 .ctl = 1,
 186                 .name = "Mic Capture Switch",
 187         },
 188         [MIXER_SPDIFI_C_S] = {
 189                 .ctl = 1,
 190                 .name = "IEC958 Capture Switch",
 191         },
 192         [MIXER_SPDIFO_P_S] = {
 193                 .ctl = 1,
 194                 .name = "Digital Playback Switch",
 195         },
 196         [MIXER_WAVEF_P_S] = {
 197                 .ctl = 1,
 198                 .name = "Front Playback Switch",
 199         },
 200         [MIXER_WAVES_P_S] = {
 201                 .ctl = 1,
 202                 .name = "Side Playback Switch",
 203         },
 204         [MIXER_WAVEC_P_S] = {
 205                 .ctl = 1,
 206                 .name = "Center/LFE Playback Switch",
 207         },
 208         [MIXER_WAVER_P_S] = {
 209                 .ctl = 1,
 210                 .name = "Surround Playback Switch",
 211         },
 212         [MIXER_DIGITAL_IO_S] = {
 213                 .ctl = 0,
 214                 .name = "Digit-IO Playback Switch",
 215         },
 216 };
 217 
 218 static void
 219 ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 220 
 221 static void
 222 ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type);
 223 
 224 /* FIXME: this static looks like it would fail if more than one card was */
 225 /* installed. */
 226 static struct snd_kcontrol *kctls[2] = {NULL};
 227 
 228 static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index)
 229 {
 230         switch (alsa_index) {
 231         case MIXER_MASTER_P:    return AMIXER_MASTER_F;
 232         case MIXER_MASTER_C:    return AMIXER_MASTER_F_C;
 233         case MIXER_PCM_P:       return AMIXER_PCM_F;
 234         case MIXER_PCM_C:
 235         case MIXER_PCM_C_S:     return AMIXER_PCM_F_C;
 236         case MIXER_LINEIN_P:    return AMIXER_LINEIN;
 237         case MIXER_LINEIN_C:
 238         case MIXER_LINEIN_C_S:  return AMIXER_LINEIN_C;
 239         case MIXER_MIC_P:       return AMIXER_MIC;
 240         case MIXER_MIC_C:
 241         case MIXER_MIC_C_S:     return AMIXER_MIC_C;
 242         case MIXER_SPDIFI_P:    return AMIXER_SPDIFI;
 243         case MIXER_SPDIFI_C:
 244         case MIXER_SPDIFI_C_S:  return AMIXER_SPDIFI_C;
 245         case MIXER_SPDIFO_P:    return AMIXER_SPDIFO;
 246         case MIXER_WAVEF_P:     return AMIXER_WAVE_F;
 247         case MIXER_WAVES_P:     return AMIXER_WAVE_S;
 248         case MIXER_WAVEC_P:     return AMIXER_WAVE_C;
 249         case MIXER_WAVER_P:     return AMIXER_WAVE_R;
 250         default:                return NUM_CT_AMIXERS;
 251         }
 252 }
 253 
 254 static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index)
 255 {
 256         switch (index) {
 257         case AMIXER_MASTER_F:   return AMIXER_MASTER_F_C;
 258         case AMIXER_PCM_F:      return AMIXER_PCM_F_C;
 259         case AMIXER_SPDIFI:     return AMIXER_SPDIFI_C;
 260         case AMIXER_LINEIN:     return AMIXER_LINEIN_C;
 261         case AMIXER_MIC:        return AMIXER_MIC_C;
 262         default:                return NUM_CT_AMIXERS;
 263         }
 264 }
 265 
 266 static unsigned char
 267 get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type)
 268 {
 269         return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START)))
 270                 ? 1 : 0;
 271 }
 272 
 273 static void
 274 set_switch_state(struct ct_mixer *mixer,
 275                  enum CTALSA_MIXER_CTL type, unsigned char state)
 276 {
 277         if (state)
 278                 mixer->switch_state |= (0x1 << (type - SWH_MIXER_START));
 279         else
 280                 mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START));
 281 }
 282 
 283 #if 0 /* not used */
 284 /* Map integer value ranging from 0 to 65535 to 14-bit float value ranging
 285  * from 2^-6 to (1+1023/1024) */
 286 static unsigned int uint16_to_float14(unsigned int x)
 287 {
 288         unsigned int i;
 289 
 290         if (x < 17)
 291                 return 0;
 292 
 293         x *= 2031;
 294         x /= 65535;
 295         x += 16;
 296 
 297         /* i <= 6 */
 298         for (i = 0; !(x & 0x400); i++)
 299                 x <<= 1;
 300 
 301         x = (((7 - i) & 0x7) << 10) | (x & 0x3ff);
 302 
 303         return x;
 304 }
 305 
 306 static unsigned int float14_to_uint16(unsigned int x)
 307 {
 308         unsigned int e;
 309 
 310         if (!x)
 311                 return x;
 312 
 313         e = (x >> 10) & 0x7;
 314         x &= 0x3ff;
 315         x += 1024;
 316         x >>= (7 - e);
 317         x -= 16;
 318         x *= 65535;
 319         x /= 2031;
 320 
 321         return x;
 322 }
 323 #endif /* not used */
 324 
 325 #define VOL_SCALE       0x1c
 326 #define VOL_MAX         0x100
 327 
 328 static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1);
 329 
 330 static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol,
 331                                    struct snd_ctl_elem_info *uinfo)
 332 {
 333         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 334         uinfo->count = 2;
 335         uinfo->value.integer.min = 0;
 336         uinfo->value.integer.max = VOL_MAX;
 337 
 338         return 0;
 339 }
 340 
 341 static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol,
 342                                   struct snd_ctl_elem_value *ucontrol)
 343 {
 344         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 345         enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
 346         struct amixer *amixer;
 347         int i, val;
 348 
 349         for (i = 0; i < 2; i++) {
 350                 amixer = ((struct ct_mixer *)atc->mixer)->
 351                                                 amixers[type*CHN_NUM+i];
 352                 val = amixer->ops->get_scale(amixer) / VOL_SCALE;
 353                 if (val < 0)
 354                         val = 0;
 355                 else if (val > VOL_MAX)
 356                         val = VOL_MAX;
 357                 ucontrol->value.integer.value[i] = val;
 358         }
 359 
 360         return 0;
 361 }
 362 
 363 static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol,
 364                                   struct snd_ctl_elem_value *ucontrol)
 365 {
 366         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 367         struct ct_mixer *mixer = atc->mixer;
 368         enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value);
 369         struct amixer *amixer;
 370         int i, j, val, oval, change = 0;
 371 
 372         for (i = 0; i < 2; i++) {
 373                 val = ucontrol->value.integer.value[i];
 374                 if (val < 0)
 375                         val = 0;
 376                 else if (val > VOL_MAX)
 377                         val = VOL_MAX;
 378                 val *= VOL_SCALE;
 379                 amixer = mixer->amixers[type*CHN_NUM+i];
 380                 oval = amixer->ops->get_scale(amixer);
 381                 if (val != oval) {
 382                         amixer->ops->set_scale(amixer, val);
 383                         amixer->ops->commit_write(amixer);
 384                         change = 1;
 385                         /* Synchronize Master/PCM playback AMIXERs. */
 386                         if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) {
 387                                 for (j = 1; j < 4; j++) {
 388                                         amixer = mixer->
 389                                                 amixers[(type+j)*CHN_NUM+i];
 390                                         amixer->ops->set_scale(amixer, val);
 391                                         amixer->ops->commit_write(amixer);
 392                                 }
 393                         }
 394                 }
 395         }
 396 
 397         return change;
 398 }
 399 
 400 static struct snd_kcontrol_new vol_ctl = {
 401         .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE |
 402                           SNDRV_CTL_ELEM_ACCESS_TLV_READ,
 403         .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
 404         .info           = ct_alsa_mix_volume_info,
 405         .get            = ct_alsa_mix_volume_get,
 406         .put            = ct_alsa_mix_volume_put,
 407         .tlv            = { .p =  ct_vol_db_scale },
 408 };
 409 
 410 static int output_switch_info(struct snd_kcontrol *kcontrol,
 411                               struct snd_ctl_elem_info *info)
 412 {
 413         static const char *const names[3] = {
 414           "FP Headphones", "Headphones", "Speakers"
 415         };
 416 
 417         return snd_ctl_enum_info(info, 1, 3, names);
 418 }
 419 
 420 static int output_switch_get(struct snd_kcontrol *kcontrol,
 421                              struct snd_ctl_elem_value *ucontrol)
 422 {
 423         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 424         ucontrol->value.enumerated.item[0] = atc->output_switch_get(atc);
 425         return 0;
 426 }
 427 
 428 static int output_switch_put(struct snd_kcontrol *kcontrol,
 429                              struct snd_ctl_elem_value *ucontrol)
 430 {
 431         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 432         if (ucontrol->value.enumerated.item[0] > 2)
 433                 return -EINVAL;
 434         return atc->output_switch_put(atc, ucontrol->value.enumerated.item[0]);
 435 }
 436 
 437 static struct snd_kcontrol_new output_ctl = {
 438         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 439         .name = "Analog Output Playback Enum",
 440         .info = output_switch_info,
 441         .get = output_switch_get,
 442         .put = output_switch_put,
 443 };
 444 
 445 static int mic_source_switch_info(struct snd_kcontrol *kcontrol,
 446                               struct snd_ctl_elem_info *info)
 447 {
 448         static const char *const names[3] = {
 449           "Mic", "FP Mic", "Aux"
 450         };
 451 
 452         return snd_ctl_enum_info(info, 1, 3, names);
 453 }
 454 
 455 static int mic_source_switch_get(struct snd_kcontrol *kcontrol,
 456                              struct snd_ctl_elem_value *ucontrol)
 457 {
 458         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 459         ucontrol->value.enumerated.item[0] = atc->mic_source_switch_get(atc);
 460         return 0;
 461 }
 462 
 463 static int mic_source_switch_put(struct snd_kcontrol *kcontrol,
 464                              struct snd_ctl_elem_value *ucontrol)
 465 {
 466         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 467         if (ucontrol->value.enumerated.item[0] > 2)
 468                 return -EINVAL;
 469         return atc->mic_source_switch_put(atc,
 470                                         ucontrol->value.enumerated.item[0]);
 471 }
 472 
 473 static struct snd_kcontrol_new mic_source_ctl = {
 474         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 475         .name = "Mic Source Capture Enum",
 476         .info = mic_source_switch_info,
 477         .get = mic_source_switch_get,
 478         .put = mic_source_switch_put,
 479 };
 480 
 481 static void
 482 do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type)
 483 {
 484 
 485         if (MIXER_LINEIN_C_S == type) {
 486                 atc->select_line_in(atc);
 487                 set_switch_state(atc->mixer, MIXER_MIC_C_S, 0);
 488                 snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
 489                                                         &kctls[1]->id);
 490         } else if (MIXER_MIC_C_S == type) {
 491                 atc->select_mic_in(atc);
 492                 set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0);
 493                 snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE,
 494                                                         &kctls[0]->id);
 495         }
 496 }
 497 
 498 static void
 499 do_digit_io_switch(struct ct_atc *atc, int state)
 500 {
 501         struct ct_mixer *mixer = atc->mixer;
 502 
 503         if (state) {
 504                 atc->select_digit_io(atc);
 505                 atc->spdif_out_unmute(atc,
 506                                 get_switch_state(mixer, MIXER_SPDIFO_P_S));
 507                 atc->spdif_in_unmute(atc, 1);
 508                 atc->line_in_unmute(atc, 0);
 509                 return;
 510         }
 511 
 512         if (get_switch_state(mixer, MIXER_LINEIN_C_S))
 513                 atc->select_line_in(atc);
 514         else if (get_switch_state(mixer, MIXER_MIC_C_S))
 515                 atc->select_mic_in(atc);
 516 
 517         atc->spdif_out_unmute(atc, 0);
 518         atc->spdif_in_unmute(atc, 0);
 519         atc->line_in_unmute(atc, 1);
 520         return;
 521 }
 522 
 523 static void do_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type, int state)
 524 {
 525         struct ct_mixer *mixer = atc->mixer;
 526         struct capabilities cap = atc->capabilities(atc);
 527 
 528         /* Do changes in mixer. */
 529         if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) {
 530                 if (state) {
 531                         ct_mixer_recording_select(mixer,
 532                                                   get_amixer_index(type));
 533                 } else {
 534                         ct_mixer_recording_unselect(mixer,
 535                                                     get_amixer_index(type));
 536                 }
 537         }
 538         /* Do changes out of mixer. */
 539         if (!cap.dedicated_mic &&
 540             (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) {
 541                 if (state)
 542                         do_line_mic_switch(atc, type);
 543                 atc->line_in_unmute(atc, state);
 544         } else if (cap.dedicated_mic && (MIXER_LINEIN_C_S == type))
 545                 atc->line_in_unmute(atc, state);
 546         else if (cap.dedicated_mic && (MIXER_MIC_C_S == type))
 547                 atc->mic_unmute(atc, state);
 548         else if (MIXER_SPDIFI_C_S == type)
 549                 atc->spdif_in_unmute(atc, state);
 550         else if (MIXER_WAVEF_P_S == type)
 551                 atc->line_front_unmute(atc, state);
 552         else if (MIXER_WAVES_P_S == type)
 553                 atc->line_surround_unmute(atc, state);
 554         else if (MIXER_WAVEC_P_S == type)
 555                 atc->line_clfe_unmute(atc, state);
 556         else if (MIXER_WAVER_P_S == type)
 557                 atc->line_rear_unmute(atc, state);
 558         else if (MIXER_SPDIFO_P_S == type)
 559                 atc->spdif_out_unmute(atc, state);
 560         else if (MIXER_DIGITAL_IO_S == type)
 561                 do_digit_io_switch(atc, state);
 562 
 563         return;
 564 }
 565 
 566 static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol,
 567                                    struct snd_ctl_elem_info *uinfo)
 568 {
 569         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
 570         uinfo->count = 1;
 571         uinfo->value.integer.min = 0;
 572         uinfo->value.integer.max = 1;
 573         uinfo->value.integer.step = 1;
 574 
 575         return 0;
 576 }
 577 
 578 static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol,
 579                                   struct snd_ctl_elem_value *ucontrol)
 580 {
 581         struct ct_mixer *mixer =
 582                 ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer;
 583         enum CTALSA_MIXER_CTL type = kcontrol->private_value;
 584 
 585         ucontrol->value.integer.value[0] = get_switch_state(mixer, type);
 586         return 0;
 587 }
 588 
 589 static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol,
 590                                   struct snd_ctl_elem_value *ucontrol)
 591 {
 592         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 593         struct ct_mixer *mixer = atc->mixer;
 594         enum CTALSA_MIXER_CTL type = kcontrol->private_value;
 595         int state;
 596 
 597         state = ucontrol->value.integer.value[0];
 598         if (get_switch_state(mixer, type) == state)
 599                 return 0;
 600 
 601         set_switch_state(mixer, type, state);
 602         do_switch(atc, type, state);
 603 
 604         return 1;
 605 }
 606 
 607 static struct snd_kcontrol_new swh_ctl = {
 608         .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 609         .iface          = SNDRV_CTL_ELEM_IFACE_MIXER,
 610         .info           = ct_alsa_mix_switch_info,
 611         .get            = ct_alsa_mix_switch_get,
 612         .put            = ct_alsa_mix_switch_put
 613 };
 614 
 615 static int ct_spdif_info(struct snd_kcontrol *kcontrol,
 616                          struct snd_ctl_elem_info *uinfo)
 617 {
 618         uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 619         uinfo->count = 1;
 620         return 0;
 621 }
 622 
 623 static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol,
 624                              struct snd_ctl_elem_value *ucontrol)
 625 {
 626         ucontrol->value.iec958.status[0] = 0xff;
 627         ucontrol->value.iec958.status[1] = 0xff;
 628         ucontrol->value.iec958.status[2] = 0xff;
 629         ucontrol->value.iec958.status[3] = 0xff;
 630         return 0;
 631 }
 632 
 633 static int ct_spdif_get(struct snd_kcontrol *kcontrol,
 634                         struct snd_ctl_elem_value *ucontrol)
 635 {
 636         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 637         unsigned int status;
 638 
 639         atc->spdif_out_get_status(atc, &status);
 640 
 641         if (status == 0)
 642                 status = SNDRV_PCM_DEFAULT_CON_SPDIF;
 643 
 644         ucontrol->value.iec958.status[0] = (status >> 0) & 0xff;
 645         ucontrol->value.iec958.status[1] = (status >> 8) & 0xff;
 646         ucontrol->value.iec958.status[2] = (status >> 16) & 0xff;
 647         ucontrol->value.iec958.status[3] = (status >> 24) & 0xff;
 648 
 649         return 0;
 650 }
 651 
 652 static int ct_spdif_put(struct snd_kcontrol *kcontrol,
 653                         struct snd_ctl_elem_value *ucontrol)
 654 {
 655         struct ct_atc *atc = snd_kcontrol_chip(kcontrol);
 656         int change;
 657         unsigned int status, old_status;
 658 
 659         status = (ucontrol->value.iec958.status[0] << 0) |
 660                  (ucontrol->value.iec958.status[1] << 8) |
 661                  (ucontrol->value.iec958.status[2] << 16) |
 662                  (ucontrol->value.iec958.status[3] << 24);
 663 
 664         atc->spdif_out_get_status(atc, &old_status);
 665         change = (old_status != status);
 666         if (change)
 667                 atc->spdif_out_set_status(atc, status);
 668 
 669         return change;
 670 }
 671 
 672 static struct snd_kcontrol_new iec958_mask_ctl = {
 673         .access         = SNDRV_CTL_ELEM_ACCESS_READ,
 674         .iface          = SNDRV_CTL_ELEM_IFACE_PCM,
 675         .name           = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
 676         .count          = 1,
 677         .info           = ct_spdif_info,
 678         .get            = ct_spdif_get_mask,
 679         .private_value  = MIXER_IEC958_MASK
 680 };
 681 
 682 static struct snd_kcontrol_new iec958_default_ctl = {
 683         .iface          = SNDRV_CTL_ELEM_IFACE_PCM,
 684         .name           = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
 685         .count          = 1,
 686         .info           = ct_spdif_info,
 687         .get            = ct_spdif_get,
 688         .put            = ct_spdif_put,
 689         .private_value  = MIXER_IEC958_DEFAULT
 690 };
 691 
 692 static struct snd_kcontrol_new iec958_ctl = {
 693         .access         = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 694         .iface          = SNDRV_CTL_ELEM_IFACE_PCM,
 695         .name           = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
 696         .count          = 1,
 697         .info           = ct_spdif_info,
 698         .get            = ct_spdif_get,
 699         .put            = ct_spdif_put,
 700         .private_value  = MIXER_IEC958_STREAM
 701 };
 702 
 703 #define NUM_IEC958_CTL 3
 704 
 705 static int
 706 ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new)
 707 {
 708         struct snd_kcontrol *kctl;
 709         int err;
 710 
 711         kctl = snd_ctl_new1(new, mixer->atc);
 712         if (!kctl)
 713                 return -ENOMEM;
 714 
 715         if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface)
 716                 kctl->id.device = IEC958;
 717 
 718         err = snd_ctl_add(mixer->atc->card, kctl);
 719         if (err)
 720                 return err;
 721 
 722         switch (new->private_value) {
 723         case MIXER_LINEIN_C_S:
 724                 kctls[0] = kctl; break;
 725         case MIXER_MIC_C_S:
 726                 kctls[1] = kctl; break;
 727         default:
 728                 break;
 729         }
 730 
 731         return 0;
 732 }
 733 
 734 static int ct_mixer_kcontrols_create(struct ct_mixer *mixer)
 735 {
 736         enum CTALSA_MIXER_CTL type;
 737         struct ct_atc *atc = mixer->atc;
 738         struct capabilities cap = atc->capabilities(atc);
 739         int err;
 740 
 741         /* Create snd kcontrol instances on demand */
 742         for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) {
 743                 if (ct_kcontrol_init_table[type].ctl) {
 744                         vol_ctl.name = ct_kcontrol_init_table[type].name;
 745                         vol_ctl.private_value = (unsigned long)type;
 746                         err = ct_mixer_kcontrol_new(mixer, &vol_ctl);
 747                         if (err)
 748                                 return err;
 749                 }
 750         }
 751 
 752         ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = cap.digit_io_switch;
 753 
 754         for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) {
 755                 if (ct_kcontrol_init_table[type].ctl) {
 756                         swh_ctl.name = ct_kcontrol_init_table[type].name;
 757                         swh_ctl.private_value = (unsigned long)type;
 758                         err = ct_mixer_kcontrol_new(mixer, &swh_ctl);
 759                         if (err)
 760                                 return err;
 761                 }
 762         }
 763 
 764         err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl);
 765         if (err)
 766                 return err;
 767 
 768         err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl);
 769         if (err)
 770                 return err;
 771 
 772         err = ct_mixer_kcontrol_new(mixer, &iec958_ctl);
 773         if (err)
 774                 return err;
 775 
 776         if (cap.output_switch) {
 777                 err = ct_mixer_kcontrol_new(mixer, &output_ctl);
 778                 if (err)
 779                         return err;
 780         }
 781 
 782         if (cap.mic_source_switch) {
 783                 err = ct_mixer_kcontrol_new(mixer, &mic_source_ctl);
 784                 if (err)
 785                         return err;
 786         }
 787         atc->line_front_unmute(atc, 1);
 788         set_switch_state(mixer, MIXER_WAVEF_P_S, 1);
 789         atc->line_surround_unmute(atc, 0);
 790         set_switch_state(mixer, MIXER_WAVES_P_S, 0);
 791         atc->line_clfe_unmute(atc, 0);
 792         set_switch_state(mixer, MIXER_WAVEC_P_S, 0);
 793         atc->line_rear_unmute(atc, 0);
 794         set_switch_state(mixer, MIXER_WAVER_P_S, 0);
 795         atc->spdif_out_unmute(atc, 0);
 796         set_switch_state(mixer, MIXER_SPDIFO_P_S, 0);
 797         atc->line_in_unmute(atc, 0);
 798         if (cap.dedicated_mic)
 799                 atc->mic_unmute(atc, 0);
 800         atc->spdif_in_unmute(atc, 0);
 801         set_switch_state(mixer, MIXER_PCM_C_S, 0);
 802         set_switch_state(mixer, MIXER_LINEIN_C_S, 0);
 803         set_switch_state(mixer, MIXER_SPDIFI_C_S, 0);
 804 
 805         return 0;
 806 }
 807 
 808 static void
 809 ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
 810 {
 811         struct amixer *amix_d;
 812         struct sum *sum_c;
 813         int i;
 814 
 815         for (i = 0; i < 2; i++) {
 816                 amix_d = mixer->amixers[type*CHN_NUM+i];
 817                 sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i];
 818                 amix_d->ops->set_sum(amix_d, sum_c);
 819                 amix_d->ops->commit_write(amix_d);
 820         }
 821 }
 822 
 823 static void
 824 ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type)
 825 {
 826         struct amixer *amix_d;
 827         int i;
 828 
 829         for (i = 0; i < 2; i++) {
 830                 amix_d = mixer->amixers[type*CHN_NUM+i];
 831                 amix_d->ops->set_sum(amix_d, NULL);
 832                 amix_d->ops->commit_write(amix_d);
 833         }
 834 }
 835 
 836 static int ct_mixer_get_resources(struct ct_mixer *mixer)
 837 {
 838         struct sum_mgr *sum_mgr;
 839         struct sum *sum;
 840         struct sum_desc sum_desc = {0};
 841         struct amixer_mgr *amixer_mgr;
 842         struct amixer *amixer;
 843         struct amixer_desc am_desc = {0};
 844         int err;
 845         int i;
 846 
 847         /* Allocate sum resources for mixer obj */
 848         sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
 849         sum_desc.msr = mixer->atc->msr;
 850         for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
 851                 err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum);
 852                 if (err) {
 853                         dev_err(mixer->atc->card->dev,
 854                                 "Failed to get sum resources for front output!\n");
 855                         break;
 856                 }
 857                 mixer->sums[i] = sum;
 858         }
 859         if (err)
 860                 goto error1;
 861 
 862         /* Allocate amixer resources for mixer obj */
 863         amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
 864         am_desc.msr = mixer->atc->msr;
 865         for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
 866                 err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer);
 867                 if (err) {
 868                         dev_err(mixer->atc->card->dev,
 869                                 "Failed to get amixer resources for mixer obj!\n");
 870                         break;
 871                 }
 872                 mixer->amixers[i] = amixer;
 873         }
 874         if (err)
 875                 goto error2;
 876 
 877         return 0;
 878 
 879 error2:
 880         for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
 881                 if (NULL != mixer->amixers[i]) {
 882                         amixer = mixer->amixers[i];
 883                         amixer_mgr->put_amixer(amixer_mgr, amixer);
 884                         mixer->amixers[i] = NULL;
 885                 }
 886         }
 887 error1:
 888         for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
 889                 if (NULL != mixer->sums[i]) {
 890                         sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
 891                         mixer->sums[i] = NULL;
 892                 }
 893         }
 894 
 895         return err;
 896 }
 897 
 898 static int ct_mixer_get_mem(struct ct_mixer **rmixer)
 899 {
 900         struct ct_mixer *mixer;
 901         int err;
 902 
 903         *rmixer = NULL;
 904         /* Allocate mem for mixer obj */
 905         mixer = kzalloc(sizeof(*mixer), GFP_KERNEL);
 906         if (!mixer)
 907                 return -ENOMEM;
 908 
 909         mixer->amixers = kcalloc(NUM_CT_AMIXERS * CHN_NUM, sizeof(void *),
 910                                  GFP_KERNEL);
 911         if (!mixer->amixers) {
 912                 err = -ENOMEM;
 913                 goto error1;
 914         }
 915         mixer->sums = kcalloc(NUM_CT_SUMS * CHN_NUM, sizeof(void *),
 916                               GFP_KERNEL);
 917         if (!mixer->sums) {
 918                 err = -ENOMEM;
 919                 goto error2;
 920         }
 921 
 922         *rmixer = mixer;
 923         return 0;
 924 
 925 error2:
 926         kfree(mixer->amixers);
 927 error1:
 928         kfree(mixer);
 929         return err;
 930 }
 931 
 932 static int ct_mixer_topology_build(struct ct_mixer *mixer)
 933 {
 934         struct sum *sum;
 935         struct amixer *amix_d, *amix_s;
 936         enum CT_AMIXER_CTL i, j;
 937         enum CT_SUM_CTL k;
 938 
 939         /* Build topology from destination to source */
 940 
 941         /* Set up Master mixer */
 942         for (i = AMIXER_MASTER_F, k = SUM_IN_F;
 943                                         i <= AMIXER_MASTER_S; i++, k++) {
 944                 amix_d = mixer->amixers[i*CHN_NUM];
 945                 sum = mixer->sums[k*CHN_NUM];
 946                 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
 947                 amix_d = mixer->amixers[i*CHN_NUM+1];
 948                 sum = mixer->sums[k*CHN_NUM+1];
 949                 amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
 950         }
 951 
 952         /* Set up Wave-out mixer */
 953         for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F;
 954                                         i <= AMIXER_WAVE_S; i++, j++) {
 955                 amix_d = mixer->amixers[i*CHN_NUM];
 956                 amix_s = mixer->amixers[j*CHN_NUM];
 957                 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
 958                 amix_d = mixer->amixers[i*CHN_NUM+1];
 959                 amix_s = mixer->amixers[j*CHN_NUM+1];
 960                 amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
 961         }
 962 
 963         /* Set up S/PDIF-out mixer */
 964         amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM];
 965         amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM];
 966         amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
 967         amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1];
 968         amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1];
 969         amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL);
 970 
 971         /* Set up PCM-in mixer */
 972         for (i = AMIXER_PCM_F, k = SUM_IN_F; i <= AMIXER_PCM_S; i++, k++) {
 973                 amix_d = mixer->amixers[i*CHN_NUM];
 974                 sum = mixer->sums[k*CHN_NUM];
 975                 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
 976                 amix_d = mixer->amixers[i*CHN_NUM+1];
 977                 sum = mixer->sums[k*CHN_NUM+1];
 978                 amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
 979         }
 980 
 981         /* Set up Line-in mixer */
 982         amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM];
 983         sum = mixer->sums[SUM_IN_F*CHN_NUM];
 984         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
 985         amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1];
 986         sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
 987         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
 988 
 989         /* Set up Mic-in mixer */
 990         amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM];
 991         sum = mixer->sums[SUM_IN_F*CHN_NUM];
 992         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
 993         amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1];
 994         sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
 995         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
 996 
 997         /* Set up S/PDIF-in mixer */
 998         amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM];
 999         sum = mixer->sums[SUM_IN_F*CHN_NUM];
1000         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1001         amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1];
1002         sum = mixer->sums[SUM_IN_F*CHN_NUM+1];
1003         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1004 
1005         /* Set up Master recording mixer */
1006         amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM];
1007         sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1008         amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
1009         amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1];
1010         sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1011         amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL);
1012 
1013         /* Set up PCM-in recording mixer */
1014         amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM];
1015         sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1016         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1017         amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1];
1018         sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1019         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1020 
1021         /* Set up Line-in recording mixer */
1022         amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM];
1023         sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1024         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1025         amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1];
1026         sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1027         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1028 
1029         /* Set up Mic-in recording mixer */
1030         amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM];
1031         sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1032         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1033         amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1];
1034         sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1035         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1036 
1037         /* Set up S/PDIF-in recording mixer */
1038         amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM];
1039         sum = mixer->sums[SUM_IN_F_C*CHN_NUM];
1040         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1041         amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1];
1042         sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1];
1043         amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum);
1044 
1045         return 0;
1046 }
1047 
1048 static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc)
1049 {
1050         amixer->ops->set_input(amixer, rsc);
1051         amixer->ops->commit_write(amixer);
1052 
1053         return 0;
1054 }
1055 
1056 static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type)
1057 {
1058         switch (type) {
1059         case MIX_WAVE_FRONT:    return AMIXER_WAVE_F;
1060         case MIX_WAVE_SURROUND: return AMIXER_WAVE_S;
1061         case MIX_WAVE_CENTLFE:  return AMIXER_WAVE_C;
1062         case MIX_WAVE_REAR:     return AMIXER_WAVE_R;
1063         case MIX_PCMO_FRONT:    return AMIXER_MASTER_F_C;
1064         case MIX_SPDIF_OUT:     return AMIXER_SPDIFO;
1065         case MIX_LINE_IN:       return AMIXER_LINEIN;
1066         case MIX_MIC_IN:        return AMIXER_MIC;
1067         case MIX_SPDIF_IN:      return AMIXER_SPDIFI;
1068         case MIX_PCMI_FRONT:    return AMIXER_PCM_F;
1069         case MIX_PCMI_SURROUND: return AMIXER_PCM_S;
1070         case MIX_PCMI_CENTLFE:  return AMIXER_PCM_C;
1071         case MIX_PCMI_REAR:     return AMIXER_PCM_R;
1072         default:                return 0;
1073         }
1074 }
1075 
1076 static int mixer_get_output_ports(struct ct_mixer *mixer,
1077                                   enum MIXER_PORT_T type,
1078                                   struct rsc **rleft, struct rsc **rright)
1079 {
1080         enum CT_AMIXER_CTL amix = port_to_amixer(type);
1081 
1082         if (NULL != rleft)
1083                 *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc;
1084 
1085         if (NULL != rright)
1086                 *rright =
1087                         &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc;
1088 
1089         return 0;
1090 }
1091 
1092 static int mixer_set_input_left(struct ct_mixer *mixer,
1093                                 enum MIXER_PORT_T type, struct rsc *rsc)
1094 {
1095         enum CT_AMIXER_CTL amix = port_to_amixer(type);
1096 
1097         mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
1098         amix = get_recording_amixer(amix);
1099         if (amix < NUM_CT_AMIXERS)
1100                 mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc);
1101 
1102         return 0;
1103 }
1104 
1105 static int
1106 mixer_set_input_right(struct ct_mixer *mixer,
1107                       enum MIXER_PORT_T type, struct rsc *rsc)
1108 {
1109         enum CT_AMIXER_CTL amix = port_to_amixer(type);
1110 
1111         mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
1112         amix = get_recording_amixer(amix);
1113         if (amix < NUM_CT_AMIXERS)
1114                 mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc);
1115 
1116         return 0;
1117 }
1118 
1119 #ifdef CONFIG_PM_SLEEP
1120 static int mixer_resume(struct ct_mixer *mixer)
1121 {
1122         int i, state;
1123         struct amixer *amixer;
1124 
1125         /* resume topology and volume gain. */
1126         for (i = 0; i < NUM_CT_AMIXERS*CHN_NUM; i++) {
1127                 amixer = mixer->amixers[i];
1128                 amixer->ops->commit_write(amixer);
1129         }
1130 
1131         /* resume switch state. */
1132         for (i = SWH_MIXER_START; i <= SWH_MIXER_END; i++) {
1133                 state = get_switch_state(mixer, i);
1134                 do_switch(mixer->atc, i, state);
1135         }
1136 
1137         return 0;
1138 }
1139 #endif
1140 
1141 int ct_mixer_destroy(struct ct_mixer *mixer)
1142 {
1143         struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM];
1144         struct amixer_mgr *amixer_mgr =
1145                         (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER];
1146         struct amixer *amixer;
1147         int i = 0;
1148 
1149         /* Release amixer resources */
1150         for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) {
1151                 if (NULL != mixer->amixers[i]) {
1152                         amixer = mixer->amixers[i];
1153                         amixer_mgr->put_amixer(amixer_mgr, amixer);
1154                 }
1155         }
1156 
1157         /* Release sum resources */
1158         for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) {
1159                 if (NULL != mixer->sums[i])
1160                         sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]);
1161         }
1162 
1163         /* Release mem assigned to mixer object */
1164         kfree(mixer->sums);
1165         kfree(mixer->amixers);
1166         kfree(mixer);
1167 
1168         return 0;
1169 }
1170 
1171 int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
1172 {
1173         struct ct_mixer *mixer;
1174         int err;
1175 
1176         *rmixer = NULL;
1177 
1178         /* Allocate mem for mixer obj */
1179         err = ct_mixer_get_mem(&mixer);
1180         if (err)
1181                 return err;
1182 
1183         mixer->switch_state = 0;
1184         mixer->atc = atc;
1185         /* Set operations */
1186         mixer->get_output_ports = mixer_get_output_ports;
1187         mixer->set_input_left = mixer_set_input_left;
1188         mixer->set_input_right = mixer_set_input_right;
1189 #ifdef CONFIG_PM_SLEEP
1190         mixer->resume = mixer_resume;
1191 #endif
1192 
1193         /* Allocate chip resources for mixer obj */
1194         err = ct_mixer_get_resources(mixer);
1195         if (err)
1196                 goto error;
1197 
1198         /* Build internal mixer topology */
1199         ct_mixer_topology_build(mixer);
1200 
1201         *rmixer = mixer;
1202 
1203         return 0;
1204 
1205 error:
1206         ct_mixer_destroy(mixer);
1207         return err;
1208 }
1209 
1210 int ct_alsa_mix_create(struct ct_atc *atc,
1211                        enum CTALSADEVS device,
1212                        const char *device_name)
1213 {
1214         int err;
1215 
1216         /* Create snd kcontrol instances on demand */
1217         /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */
1218         err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer);
1219         if (err)
1220                 return err;
1221 
1222         strcpy(atc->card->mixername, device_name);
1223 
1224         return 0;
1225 }

/* [<][>][^][v][top][bottom][index][help] */