diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-12-19 06:13:18 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-12-19 06:13:18 -0500 |
commit | 3d4758299fa6180ff9304634c67ffdd44272c8e8 (patch) | |
tree | c3ba2244cd191cfc4b9904b076e8d61fc9fb8834 /sound | |
parent | 86effd7e12ca63cecfd218717473d606e138e5e1 (diff) |
ALSA: ca0106 - Add IEC958 PCM Stream controls
Added "IEC958 PCM Stream" controls for the per-stream IEC958 status
bits. Using this instead of "IEC958 Default" is safer since the status
bits will be recovered to the default states after closing the PCM
stream.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-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 1c14ff424116..ec0f17ded4e0 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
@@ -690,7 +690,8 @@ struct snd_ca0106 { | |||
690 | 690 | ||
691 | struct snd_ca0106_channel playback_channels[4]; | 691 | struct snd_ca0106_channel playback_channels[4]; |
692 | struct snd_ca0106_channel capture_channels[4]; | 692 | struct snd_ca0106_channel capture_channels[4]; |
693 | u32 spdif_bits[4]; /* s/pdif out setup */ | 693 | u32 spdif_bits[4]; /* s/pdif out default setup */ |
694 | u32 spdif_str_bits[4]; /* s/pdif out per-stream setup */ | ||
694 | int spdif_enable; | 695 | int spdif_enable; |
695 | int capture_source; | 696 | int capture_source; |
696 | int i2c_capture_source; | 697 | int i2c_capture_source; |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 2c71f9b896cd..c27fd90101d6 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -479,6 +479,15 @@ static const int spi_dacd_bit[] = { | |||
479 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, | 479 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, |
480 | }; | 480 | }; |
481 | 481 | ||
482 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | ||
483 | { | ||
484 | if (chip->spdif_str_bits[idx] != chip->spdif_bits[idx]) { | ||
485 | chip->spdif_str_bits[idx] = chip->spdif_bits[idx]; | ||
486 | snd_ca0106_ptr_write(chip, SPCS0 + idx, 0, | ||
487 | chip->spdif_str_bits[idx]); | ||
488 | } | ||
489 | } | ||
490 | |||
482 | /* open_playback callback */ | 491 | /* open_playback callback */ |
483 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, | 492 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, |
484 | int channel_id) | 493 | int channel_id) |
@@ -524,6 +533,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr | |||
524 | if (err < 0) | 533 | if (err < 0) |
525 | return err; | 534 | return err; |
526 | } | 535 | } |
536 | |||
537 | restore_spdif_bits(chip, channel_id); | ||
538 | |||
527 | return 0; | 539 | return 0; |
528 | } | 540 | } |
529 | 541 | ||
@@ -535,6 +547,8 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) | |||
535 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 547 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
536 | chip->playback_channels[epcm->channel_id].use = 0; | 548 | chip->playback_channels[epcm->channel_id].use = 0; |
537 | 549 | ||
550 | restore_spdif_bits(chip, epcm->channel_id); | ||
551 | |||
538 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { | 552 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { |
539 | const int reg = spi_dacd_reg[epcm->channel_id]; | 553 | const int reg = spi_dacd_reg[epcm->channel_id]; |
540 | 554 | ||
@@ -1330,16 +1344,16 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
1330 | SPCS_GENERATIONSTATUS | 0x00001200 | | 1344 | SPCS_GENERATIONSTATUS | 0x00001200 | |
1331 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; | 1345 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT; |
1332 | if (!resume) { | 1346 | if (!resume) { |
1333 | chip->spdif_bits[0] = def_bits; | 1347 | chip->spdif_str_bits[0] = chip->spdif_bits[0] = def_bits; |
1334 | chip->spdif_bits[1] = def_bits; | 1348 | chip->spdif_str_bits[1] = chip->spdif_bits[1] = def_bits; |
1335 | chip->spdif_bits[2] = def_bits; | 1349 | chip->spdif_str_bits[2] = chip->spdif_bits[2] = def_bits; |
1336 | chip->spdif_bits[3] = def_bits; | 1350 | chip->spdif_str_bits[3] = chip->spdif_bits[3] = def_bits; |
1337 | } | 1351 | } |
1338 | /* Only SPCS1 has been tested */ | 1352 | /* Only SPCS1 has been tested */ |
1339 | snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1]); | 1353 | snd_ca0106_ptr_write(chip, SPCS1, 0, chip->spdif_str_bits[1]); |
1340 | snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0]); | 1354 | snd_ca0106_ptr_write(chip, SPCS0, 0, chip->spdif_str_bits[0]); |
1341 | snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2]); | 1355 | snd_ca0106_ptr_write(chip, SPCS2, 0, chip->spdif_str_bits[2]); |
1342 | snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_bits[3]); | 1356 | snd_ca0106_ptr_write(chip, SPCS3, 0, chip->spdif_str_bits[3]); |
1343 | 1357 | ||
1344 | snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); | 1358 | snd_ca0106_ptr_write(chip, PLAYBACK_MUTE, 0, 0x00fc0000); |
1345 | snd_ca0106_ptr_write(chip, CAPTURE_MUTE, 0, 0x00fc0000); | 1359 | 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 cccc32cdb943..8727881a10b8 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 | ||