diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/cmipci.c | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 085a36751ac0..6832649879ce 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -434,6 +434,7 @@ struct cmipci_pcm { | |||
434 | u8 running; /* dac/adc running? */ | 434 | u8 running; /* dac/adc running? */ |
435 | u8 fmt; /* format bits */ | 435 | u8 fmt; /* format bits */ |
436 | u8 is_dac; | 436 | u8 is_dac; |
437 | u8 needs_silencing; | ||
437 | unsigned int dma_size; /* in frames */ | 438 | unsigned int dma_size; /* in frames */ |
438 | unsigned int shift; | 439 | unsigned int shift; |
439 | unsigned int ch; /* channel (0/1) */ | 440 | unsigned int ch; /* channel (0/1) */ |
@@ -903,6 +904,7 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, | |||
903 | cm->ctrl &= ~chen; | 904 | cm->ctrl &= ~chen; |
904 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset); | 905 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | reset); |
905 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); | 906 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~reset); |
907 | rec->needs_silencing = rec->is_dac; | ||
906 | break; | 908 | break; |
907 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 909 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
908 | case SNDRV_PCM_TRIGGER_SUSPEND: | 910 | case SNDRV_PCM_TRIGGER_SUSPEND: |
@@ -1304,11 +1306,75 @@ static int snd_cmipci_playback_spdif_prepare(struct snd_pcm_substream *substream | |||
1304 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); | 1306 | return snd_cmipci_pcm_prepare(cm, &cm->channel[CM_CH_PLAY], substream); |
1305 | } | 1307 | } |
1306 | 1308 | ||
1309 | /* | ||
1310 | * Apparently, the samples last played on channel A stay in some buffer, even | ||
1311 | * after the channel is reset, and get added to the data for the rear DACs when | ||
1312 | * playing a multichannel stream on channel B. This is likely to generate | ||
1313 | * wraparounds and thus distortions. | ||
1314 | * To avoid this, we play at least one zero sample after the actual stream has | ||
1315 | * stopped. | ||
1316 | */ | ||
1317 | static void snd_cmipci_silence_hack(struct cmipci *cm, struct cmipci_pcm *rec) | ||
1318 | { | ||
1319 | struct snd_pcm_runtime *runtime = rec->substream->runtime; | ||
1320 | unsigned int reg, val; | ||
1321 | |||
1322 | if (rec->needs_silencing && runtime && runtime->dma_area) { | ||
1323 | /* set up a small silence buffer */ | ||
1324 | memset(runtime->dma_area, 0, PAGE_SIZE); | ||
1325 | reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; | ||
1326 | val = ((PAGE_SIZE / 4) - 1) | (((PAGE_SIZE / 4) / 2 - 1) << 16); | ||
1327 | snd_cmipci_write(cm, reg, val); | ||
1328 | |||
1329 | /* configure for 16 bits, 2 channels, 8 kHz */ | ||
1330 | if (runtime->channels > 2) | ||
1331 | set_dac_channels(cm, rec, 2); | ||
1332 | spin_lock_irq(&cm->reg_lock); | ||
1333 | val = snd_cmipci_read(cm, CM_REG_FUNCTRL1); | ||
1334 | val &= ~(CM_ASFC_MASK << (rec->ch * 3)); | ||
1335 | val |= (4 << CM_ASFC_SHIFT) << (rec->ch * 3); | ||
1336 | snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); | ||
1337 | val = snd_cmipci_read(cm, CM_REG_CHFORMAT); | ||
1338 | val &= ~(CM_CH0FMT_MASK << (rec->ch * 2)); | ||
1339 | val |= (3 << CM_CH0FMT_SHIFT) << (rec->ch * 2); | ||
1340 | if (cm->chip_version == 68) { | ||
1341 | val &= ~(CM_CH0_SRATE_88K << (rec->ch * 2)); | ||
1342 | val &= ~(CM_CH0_SRATE_96K << (rec->ch * 2)); | ||
1343 | } | ||
1344 | snd_cmipci_write(cm, CM_REG_CHFORMAT, val); | ||
1345 | |||
1346 | /* start stream (we don't need interrupts) */ | ||
1347 | cm->ctrl |= CM_CHEN0 << rec->ch; | ||
1348 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); | ||
1349 | spin_unlock_irq(&cm->reg_lock); | ||
1350 | |||
1351 | msleep(1); | ||
1352 | |||
1353 | /* stop and reset stream */ | ||
1354 | spin_lock_irq(&cm->reg_lock); | ||
1355 | cm->ctrl &= ~(CM_CHEN0 << rec->ch); | ||
1356 | val = CM_RST_CH0 << rec->ch; | ||
1357 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl | val); | ||
1358 | snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl & ~val); | ||
1359 | spin_unlock_irq(&cm->reg_lock); | ||
1360 | |||
1361 | rec->needs_silencing = 0; | ||
1362 | } | ||
1363 | } | ||
1364 | |||
1307 | static int snd_cmipci_playback_hw_free(struct snd_pcm_substream *substream) | 1365 | static int snd_cmipci_playback_hw_free(struct snd_pcm_substream *substream) |
1308 | { | 1366 | { |
1309 | struct cmipci *cm = snd_pcm_substream_chip(substream); | 1367 | struct cmipci *cm = snd_pcm_substream_chip(substream); |
1310 | setup_spdif_playback(cm, substream, 0, 0); | 1368 | setup_spdif_playback(cm, substream, 0, 0); |
1311 | restore_mixer_state(cm); | 1369 | restore_mixer_state(cm); |
1370 | snd_cmipci_silence_hack(cm, &cm->channel[0]); | ||
1371 | return snd_cmipci_hw_free(substream); | ||
1372 | } | ||
1373 | |||
1374 | static int snd_cmipci_playback2_hw_free(struct snd_pcm_substream *substream) | ||
1375 | { | ||
1376 | struct cmipci *cm = snd_pcm_substream_chip(substream); | ||
1377 | snd_cmipci_silence_hack(cm, &cm->channel[1]); | ||
1312 | return snd_cmipci_hw_free(substream); | 1378 | return snd_cmipci_hw_free(substream); |
1313 | } | 1379 | } |
1314 | 1380 | ||
@@ -1736,7 +1802,7 @@ static struct snd_pcm_ops snd_cmipci_playback2_ops = { | |||
1736 | .close = snd_cmipci_playback2_close, | 1802 | .close = snd_cmipci_playback2_close, |
1737 | .ioctl = snd_pcm_lib_ioctl, | 1803 | .ioctl = snd_pcm_lib_ioctl, |
1738 | .hw_params = snd_cmipci_playback2_hw_params, | 1804 | .hw_params = snd_cmipci_playback2_hw_params, |
1739 | .hw_free = snd_cmipci_hw_free, | 1805 | .hw_free = snd_cmipci_playback2_hw_free, |
1740 | .prepare = snd_cmipci_capture_prepare, /* channel B */ | 1806 | .prepare = snd_cmipci_capture_prepare, /* channel B */ |
1741 | .trigger = snd_cmipci_capture_trigger, /* channel B */ | 1807 | .trigger = snd_cmipci_capture_trigger, /* channel B */ |
1742 | .pointer = snd_cmipci_capture_pointer, /* channel B */ | 1808 | .pointer = snd_cmipci_capture_pointer, /* channel B */ |