Commit ef18beded8ddbaafdf4914bab209f77e60ae3a18

Authored by Wu Fengguang
Committed by Takashi Iwai
1 parent 6b7b284958

ALSA: hda - HDMI sticky stream tag support

When we run the following commands in turn (with
CONFIG_SND_HDA_POWER_SAVE_DEFAULT=0),

	speaker-test -Dhw:0,3 -c2 -twav  # HDMI
	speaker-test -Dhw:0,0 -c2 -twav  # Analog

The second command will produce sound in the analog lineout _as well as_
HDMI sink. The root cause is, device 0 "reuses" the same stream tag that
was used by device 3, and the "intelhdmi - sticky stream id" patch leaves
the HDMI codec in a functional state. So the HDMI codec happily accepts
the audio samples which reuse its stream tag.

The proposed solution is to remember the last device each azx_dev was
assigned to, and prefer to
1) reuse the azx_dev (and hence the stream tag) the HDMI codec last used
2) or assign a never-used azx_dev for HDMI

With this patch and the above two speaker-test commands,
HDMI codec will use stream tag 8 and Analog codec will use 5.

The stream tag used by HDMI codec won't be reused by others, as long
as we don't run out of the 4 playback azx_dev's. The legacy Analog
codec will continue to use stream tag 5 because its device id is 0
(this is a bit tricky).

Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

Showing 1 changed file with 15 additions and 6 deletions Side-by-side Diff

sound/pci/hda/hda_intel.c
... ... @@ -356,6 +356,7 @@
356 356 */
357 357 unsigned char stream_tag; /* assigned stream */
358 358 unsigned char index; /* stream index */
  359 + int device; /* last device number assigned to */
359 360  
360 361 unsigned int opened :1;
361 362 unsigned int running :1;
362 363  
... ... @@ -1441,10 +1442,13 @@
1441 1442 */
1442 1443  
1443 1444 /* assign a stream for the PCM */
1444   -static inline struct azx_dev *azx_assign_device(struct azx *chip, int stream)
  1445 +static inline struct azx_dev *
  1446 +azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
1445 1447 {
1446 1448 int dev, i, nums;
1447   - if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
  1449 + struct azx_dev *res = NULL;
  1450 +
  1451 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1448 1452 dev = chip->playback_index_offset;
1449 1453 nums = chip->playback_streams;
1450 1454 } else {
1451 1455  
... ... @@ -1453,10 +1457,15 @@
1453 1457 }
1454 1458 for (i = 0; i < nums; i++, dev++)
1455 1459 if (!chip->azx_dev[dev].opened) {
1456   - chip->azx_dev[dev].opened = 1;
1457   - return &chip->azx_dev[dev];
  1460 + res = &chip->azx_dev[dev];
  1461 + if (res->device == substream->pcm->device)
  1462 + break;
1458 1463 }
1459   - return NULL;
  1464 + if (res) {
  1465 + res->opened = 1;
  1466 + res->device = substream->pcm->device;
  1467 + }
  1468 + return res;
1460 1469 }
1461 1470  
1462 1471 /* release the assigned stream */
... ... @@ -1505,7 +1514,7 @@
1505 1514 int err;
1506 1515  
1507 1516 mutex_lock(&chip->open_mutex);
1508   - azx_dev = azx_assign_device(chip, substream->stream);
  1517 + azx_dev = azx_assign_device(chip, substream);
1509 1518 if (azx_dev == NULL) {
1510 1519 mutex_unlock(&chip->open_mutex);
1511 1520 return -EBUSY;