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 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 | ||
