diff options
-rw-r--r-- | sound/pci/ca0106/ca0106.h | 3 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106_main.c | 30 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106_mixer.c | 83 |
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 | ||
488 | static 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 */ |
489 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, | 498 | static 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 | ||
149 | static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx) | 149 | static 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 | ||
356 | static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, | 356 | static 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 | |||
364 | static 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 | |||
375 | static 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 | ||
379 | static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, | 396 | static 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 | |||
404 | static 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 | |||
424 | static 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 | ||
399 | static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, | 440 | static 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 | ||