aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/pci/ca0106/ca0106.h3
-rw-r--r--sound/pci/ca0106/ca0106_main.c30
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c83
3 files changed, 90 insertions, 26 deletions
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index a6943cb0d209..14b8d9a91aae 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -694,7 +694,8 @@ struct snd_ca0106 {
694 694
695 struct snd_ca0106_channel playback_channels[4]; 695 struct snd_ca0106_channel playback_channels[4];
696 struct snd_ca0106_channel capture_channels[4]; 696 struct snd_ca0106_channel capture_channels[4];
697 u32 spdif_bits[4]; /* s/pdif out setup */ 697 u32 spdif_bits[4]; /* s/pdif out default setup */
698 u32 spdif_str_bits[4]; /* s/pdif out per-stream setup */
698 int spdif_enable; 699 int spdif_enable;
699 int capture_source; 700 int capture_source;
700 int i2c_capture_source; 701 int i2c_capture_source;
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 3e6dda37ef21..0e62205d4081 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -485,6 +485,15 @@ static const int spi_dacd_bit[] = {
485 [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, 485 [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT,
486}; 486};
487 487
488static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
489{
490 if (chip->spdif_str_bits[idx] != chip->spdif_bits[idx]) {
491 chip->spdif_str_bits[idx] = chip->spdif_bits[idx];
492 snd_ca0106_ptr_write(chip, SPCS0 + idx, 0,
493 chip->spdif_str_bits[idx]);
494 }
495}
496
488/* open_playback callback */ 497/* open_playback callback */
489static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, 498static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
490 int channel_id) 499 int channel_id)
@@ -530,6 +539,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
530 if (err < 0) 539 if (err < 0)
531 return err; 540 return err;
532 } 541 }
542
543 restore_spdif_bits(chip, channel_id);
544
533 return 0; 545 return 0;
534} 546}
535 547
@@ -541,6 +553,8 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
541 struct snd_ca0106_pcm *epcm = runtime->private_data; 553 struct snd_ca0106_pcm *epcm = runtime->private_data;
542 chip->playback_channels[epcm->channel_id].use = 0; 554 chip->playback_channels[epcm->channel_id].use = 0;
543 555
556 restore_spdif_bits(chip, epcm->channel_id);
557
544 if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { 558 if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
545 const int reg = spi_dacd_reg[epcm->channel_id]; 559 const int reg = spi_dacd_reg[epcm->channel_id];
546 560
@@ -1336,16 +1350,16 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
1336 SPCS_GENERATIONSTATUS | 0x00001200 | 1350 SPCS_GENERATIONSTATUS | 0x00001200 |
1337 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; 1351 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
1338 if (!resume) { 1352 if (!resume) {
1339 chip->spdif_bits[0] = def_bits; 1353 chip->spdif_str_bits[0] = chip->spdif_bits[0] = def_bits;
1340 chip->spdif_bits[1] = def_bits; 1354 chip->spdif_str_bits[1] = chip->spdif_bits[1] = def_bits;
1341 chip->spdif_bits[2] = def_bits; 1355 chip->spdif_str_bits[2] = chip->spdif_bits[2] = def_bits;
1342 chip->spdif_bits[3] = def_bits; 1356 chip->spdif_str_bits[3] = chip->spdif_bits[3] = def_bits;
1343 } 1357 }
1344 /* Only SPCS1 has been tested */ 1358 /* Only SPCS1 has been tested */
1345 snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); 1359 snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_str_bits[1]);
1346 snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); 1360 snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_str_bits[0]);
1347 snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); 1361 snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_str_bits[2]);
1348 snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); 1362 snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_str_bits[3]);
1349 1363
1350 snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); 1364 snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000);
1351 snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); 1365 snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000);
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 9845a20f5427..ad2888705d2a 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -148,7 +148,7 @@ static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
148 148
149static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) 149static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx)
150{ 150{
151 snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_bits[idx]); 151 snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]);
152} 152}
153 153
154/* 154/*
@@ -353,16 +353,33 @@ static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
353 return 0; 353 return 0;
354} 354}
355 355
356static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, 356static void decode_spdif_bits(unsigned char *status, unsigned int bits)
357{
358 status[0] = (bits >> 0) & 0xff;
359 status[1] = (bits >> 8) & 0xff;
360 status[2] = (bits >> 16) & 0xff;
361 status[3] = (bits >> 24) & 0xff;
362}
363
364static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol,
357 struct snd_ctl_elem_value *ucontrol) 365 struct snd_ctl_elem_value *ucontrol)
358{ 366{
359 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 367 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
360 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 368 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
361 369
362 ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 370 decode_spdif_bits(ucontrol->value.iec958.status,
363 ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 371 emu->spdif_bits[idx]);
364 ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 372 return 0;
365 ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 373}
374
375static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol,
376 struct snd_ctl_elem_value *ucontrol)
377{
378 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
379 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
380
381 decode_spdif_bits(ucontrol->value.iec958.status,
382 emu->spdif_str_bits[idx]);
366 return 0; 383 return 0;
367} 384}
368 385
@@ -376,24 +393,48 @@ static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
376 return 0; 393 return 0;
377} 394}
378 395
379static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, 396static unsigned int encode_spdif_bits(unsigned char *status)
397{
398 return ((unsigned int)status[0] << 0) |
399 ((unsigned int)status[1] << 8) |
400 ((unsigned int)status[2] << 16) |
401 ((unsigned int)status[3] << 24);
402}
403
404static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol,
380 struct snd_ctl_elem_value *ucontrol) 405 struct snd_ctl_elem_value *ucontrol)
381{ 406{
382 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 407 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
383 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 408 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
384 int change;
385 unsigned int val; 409 unsigned int val;
386 410
387 val = (ucontrol->value.iec958.status[0] << 0) | 411 val = encode_spdif_bits(ucontrol->value.iec958.status);
388 (ucontrol->value.iec958.status[1] << 8) | 412 if (val != emu->spdif_bits[idx]) {
389 (ucontrol->value.iec958.status[2] << 16) |
390 (ucontrol->value.iec958.status[3] << 24);
391 change = val != emu->spdif_bits[idx];
392 if (change) {
393 emu->spdif_bits[idx] = val; 413 emu->spdif_bits[idx] = val;
414 /* FIXME: this isn't safe, but needed to keep the compatibility
415 * with older alsa-lib config
416 */
417 emu->spdif_str_bits[idx] = val;
394 ca0106_set_spdif_bits(emu, idx); 418 ca0106_set_spdif_bits(emu, idx);
419 return 1;
395 } 420 }
396 return change; 421 return 0;
422}
423
424static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol,
425 struct snd_ctl_elem_value *ucontrol)
426{
427 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
428 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
429 unsigned int val;
430
431 val = encode_spdif_bits(ucontrol->value.iec958.status);
432 if (val != emu->spdif_str_bits[idx]) {
433 emu->spdif_str_bits[idx] = val;
434 ca0106_set_spdif_bits(emu, idx);
435 return 1;
436 }
437 return 0;
397} 438}
398 439
399static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, 440static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
@@ -604,8 +645,16 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
604 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 645 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
605 .count = 4, 646 .count = 4,
606 .info = snd_ca0106_spdif_info, 647 .info = snd_ca0106_spdif_info,
607 .get = snd_ca0106_spdif_get, 648 .get = snd_ca0106_spdif_get_default,
608 .put = snd_ca0106_spdif_put 649 .put = snd_ca0106_spdif_put_default
650 },
651 {
652 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
653 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
654 .count = 4,
655 .info = snd_ca0106_spdif_info,
656 .get = snd_ca0106_spdif_get_stream,
657 .put = snd_ca0106_spdif_put_stream
609 }, 658 },
610}; 659};
611 660