aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-11-27 08:17:01 -0500
committerTakashi Iwai <tiwai@suse.de>2008-11-27 08:17:01 -0500
commit529bd6c4a63f8468fd66f63fdc22d7070439b3cd (patch)
tree3a45f17bbd45ef3e4ea785ce0bb79e6afef3e438 /sound/pci/hda
parentfee2fba3586f78762ecc5f432dfd3602765a31b3 (diff)
ALSA: hda - Fix PCM reconfigure
The reconfiguration of PCM affected all PCM streams on the bus, but this this should be done rather only for the target codec. This patch does the following: - introduce bitmap indicating the PCM device usages on a hda_bus - refactor the PCM build functions - fix __devinit prefix in some fucntions - add a proper ifdef around HDA-reconfig-specific functions Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c162
-rw-r--r--sound/pci/hda/hda_codec.h4
-rw-r--r--sound/pci/hda/hda_hwdep.c2
3 files changed, 98 insertions, 70 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 052a898a63ba..1cb85b73e19b 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1206,6 +1206,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl)
1206 return 0; 1206 return 0;
1207} 1207}
1208 1208
1209#ifdef CONFIG_SND_HDA_RECONFIG
1209/* Clear all controls assigned to the given codec */ 1210/* Clear all controls assigned to the given codec */
1210void snd_hda_ctls_clear(struct hda_codec *codec) 1211void snd_hda_ctls_clear(struct hda_codec *codec)
1211{ 1212{
@@ -1227,9 +1228,12 @@ void snd_hda_codec_reset(struct hda_codec *codec)
1227 snd_hda_ctls_clear(codec); 1228 snd_hda_ctls_clear(codec);
1228 /* relase PCMs */ 1229 /* relase PCMs */
1229 for (i = 0; i < codec->num_pcms; i++) { 1230 for (i = 0; i < codec->num_pcms; i++) {
1230 if (codec->pcm_info[i].pcm) 1231 if (codec->pcm_info[i].pcm) {
1231 snd_device_free(codec->bus->card, 1232 snd_device_free(codec->bus->card,
1232 codec->pcm_info[i].pcm); 1233 codec->pcm_info[i].pcm);
1234 clear_bit(codec->pcm_info[i].device,
1235 codec->bus->pcm_dev_bits);
1236 }
1233 } 1237 }
1234 if (codec->patch_ops.free) 1238 if (codec->patch_ops.free)
1235 codec->patch_ops.free(codec); 1239 codec->patch_ops.free(codec);
@@ -1240,6 +1244,7 @@ void snd_hda_codec_reset(struct hda_codec *codec)
1240 codec->pcm_info = NULL; 1244 codec->pcm_info = NULL;
1241 codec->preset = NULL; 1245 codec->preset = NULL;
1242} 1246}
1247#endif /* CONFIG_SND_HDA_RECONFIG */
1243 1248
1244/* create a virtual master control and add slaves */ 1249/* create a virtual master control and add slaves */
1245int snd_hda_add_vmaster(struct hda_codec *codec, char *name, 1250int snd_hda_add_vmaster(struct hda_codec *codec, char *name,
@@ -2433,10 +2438,58 @@ static int set_pcm_default_values(struct hda_codec *codec,
2433} 2438}
2434 2439
2435/* 2440/*
2441 * get the empty PCM device number to assign
2442 */
2443static int get_empty_pcm_device(struct hda_bus *bus, int type)
2444{
2445 static const char *dev_name[HDA_PCM_NTYPES] = {
2446 "Audio", "SPDIF", "HDMI", "Modem"
2447 };
2448 /* starting device index for each PCM type */
2449 static int dev_idx[HDA_PCM_NTYPES] = {
2450 [HDA_PCM_TYPE_AUDIO] = 0,
2451 [HDA_PCM_TYPE_SPDIF] = 1,
2452 [HDA_PCM_TYPE_HDMI] = 3,
2453 [HDA_PCM_TYPE_MODEM] = 6
2454 };
2455 /* normal audio device indices; not linear to keep compatibility */
2456 static int audio_idx[4] = { 0, 2, 4, 5 };
2457 int i, dev;
2458
2459 switch (type) {
2460 case HDA_PCM_TYPE_AUDIO:
2461 for (i = 0; i < ARRAY_SIZE(audio_idx); i++) {
2462 dev = audio_idx[i];
2463 if (!test_bit(dev, bus->pcm_dev_bits))
2464 break;
2465 }
2466 if (i >= ARRAY_SIZE(audio_idx)) {
2467 snd_printk(KERN_WARNING "Too many audio devices\n");
2468 return -EAGAIN;
2469 }
2470 break;
2471 case HDA_PCM_TYPE_SPDIF:
2472 case HDA_PCM_TYPE_HDMI:
2473 case HDA_PCM_TYPE_MODEM:
2474 dev = dev_idx[type];
2475 if (test_bit(dev, bus->pcm_dev_bits)) {
2476 snd_printk(KERN_WARNING "%s already defined\n",
2477 dev_name[type]);
2478 return -EAGAIN;
2479 }
2480 break;
2481 default:
2482 snd_printk(KERN_WARNING "Invalid PCM type %d\n", type);
2483 return -EINVAL;
2484 }
2485 set_bit(dev, bus->pcm_dev_bits);
2486 return dev;
2487}
2488
2489/*
2436 * attach a new PCM stream 2490 * attach a new PCM stream
2437 */ 2491 */
2438static int __devinit 2492static int snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
2439snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
2440{ 2493{
2441 struct hda_bus *bus = codec->bus; 2494 struct hda_bus *bus = codec->bus;
2442 struct hda_pcm_stream *info; 2495 struct hda_pcm_stream *info;
@@ -2455,6 +2508,39 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
2455 return bus->ops.attach_pcm(bus, codec, pcm); 2508 return bus->ops.attach_pcm(bus, codec, pcm);
2456} 2509}
2457 2510
2511/* assign all PCMs of the given codec */
2512int snd_hda_codec_build_pcms(struct hda_codec *codec)
2513{
2514 unsigned int pcm;
2515 int err;
2516
2517 if (!codec->num_pcms) {
2518 if (!codec->patch_ops.build_pcms)
2519 return 0;
2520 err = codec->patch_ops.build_pcms(codec);
2521 if (err < 0)
2522 return err;
2523 }
2524 for (pcm = 0; pcm < codec->num_pcms; pcm++) {
2525 struct hda_pcm *cpcm = &codec->pcm_info[pcm];
2526 int dev;
2527
2528 if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
2529 return 0; /* no substreams assigned */
2530
2531 if (!cpcm->pcm) {
2532 dev = get_empty_pcm_device(codec->bus, cpcm->pcm_type);
2533 if (dev < 0)
2534 return 0;
2535 cpcm->device = dev;
2536 err = snd_hda_attach_pcm(codec, cpcm);
2537 if (err < 0)
2538 return err;
2539 }
2540 }
2541 return 0;
2542}
2543
2458/** 2544/**
2459 * snd_hda_build_pcms - build PCM information 2545 * snd_hda_build_pcms - build PCM information
2460 * @bus: the BUS 2546 * @bus: the BUS
@@ -2481,76 +2567,14 @@ snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
2481 * 2567 *
2482 * This function returns 0 if successfull, or a negative error code. 2568 * This function returns 0 if successfull, or a negative error code.
2483 */ 2569 */
2484int snd_hda_build_pcms(struct hda_bus *bus) 2570int __devinit snd_hda_build_pcms(struct hda_bus *bus)
2485{ 2571{
2486 static const char *dev_name[HDA_PCM_NTYPES] = {
2487 "Audio", "SPDIF", "HDMI", "Modem"
2488 };
2489 /* starting device index for each PCM type */
2490 static int dev_idx[HDA_PCM_NTYPES] = {
2491 [HDA_PCM_TYPE_AUDIO] = 0,
2492 [HDA_PCM_TYPE_SPDIF] = 1,
2493 [HDA_PCM_TYPE_HDMI] = 3,
2494 [HDA_PCM_TYPE_MODEM] = 6
2495 };
2496 /* normal audio device indices; not linear to keep compatibility */
2497 static int audio_idx[4] = { 0, 2, 4, 5 };
2498 struct hda_codec *codec; 2572 struct hda_codec *codec;
2499 int num_devs[HDA_PCM_NTYPES];
2500 2573
2501 memset(num_devs, 0, sizeof(num_devs));
2502 list_for_each_entry(codec, &bus->codec_list, list) { 2574 list_for_each_entry(codec, &bus->codec_list, list) {
2503 unsigned int pcm; 2575 int err = snd_hda_codec_build_pcms(codec);
2504 int err; 2576 if (err < 0)
2505 if (!codec->num_pcms) { 2577 return err;
2506 if (!codec->patch_ops.build_pcms)
2507 continue;
2508 err = codec->patch_ops.build_pcms(codec);
2509 if (err < 0)
2510 return err;
2511 }
2512 for (pcm = 0; pcm < codec->num_pcms; pcm++) {
2513 struct hda_pcm *cpcm = &codec->pcm_info[pcm];
2514 int type = cpcm->pcm_type;
2515 int dev;
2516
2517 if (!cpcm->stream[0].substreams &&
2518 !cpcm->stream[1].substreams)
2519 continue; /* no substreams assigned */
2520
2521 switch (type) {
2522 case HDA_PCM_TYPE_AUDIO:
2523 if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
2524 snd_printk(KERN_WARNING
2525 "Too many audio devices\n");
2526 continue;
2527 }
2528 dev = audio_idx[num_devs[type]];
2529 break;
2530 case HDA_PCM_TYPE_SPDIF:
2531 case HDA_PCM_TYPE_HDMI:
2532 case HDA_PCM_TYPE_MODEM:
2533 if (num_devs[type]) {
2534 snd_printk(KERN_WARNING
2535 "%s already defined\n",
2536 dev_name[type]);
2537 continue;
2538 }
2539 dev = dev_idx[type];
2540 break;
2541 default:
2542 snd_printk(KERN_WARNING
2543 "Invalid PCM type %d\n", type);
2544 continue;
2545 }
2546 num_devs[type]++;
2547 if (!cpcm->pcm) {
2548 cpcm->device = dev;
2549 err = snd_hda_attach_pcm(codec, cpcm);
2550 if (err < 0)
2551 return err;
2552 }
2553 }
2554 } 2578 }
2555 return 0; 2579 return 0;
2556} 2580}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 4034625b5997..9fe0b67bb1e4 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -617,6 +617,9 @@ struct hda_bus {
617 617
618 struct snd_info_entry *proc; 618 struct snd_info_entry *proc;
619 619
620 /* assigned PCMs */
621 DECLARE_BITMAP(pcm_dev_bits, SNDRV_PCM_DEVICES);
622
620 /* misc op flags */ 623 /* misc op flags */
621 unsigned int needs_damn_long_delay :1; 624 unsigned int needs_damn_long_delay :1;
622 unsigned int shutdown :1; /* being unloaded */ 625 unsigned int shutdown :1; /* being unloaded */
@@ -846,6 +849,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec);
846 * PCM 849 * PCM
847 */ 850 */
848int snd_hda_build_pcms(struct hda_bus *bus); 851int snd_hda_build_pcms(struct hda_bus *bus);
852int snd_hda_codec_build_pcms(struct hda_codec *codec);
849void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, 853void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid,
850 u32 stream_tag, 854 u32 stream_tag,
851 int channel_id, int format); 855 int channel_id, int format);
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c
index 5868bbc131cd..173af489322f 100644
--- a/sound/pci/hda/hda_hwdep.c
+++ b/sound/pci/hda/hda_hwdep.c
@@ -168,7 +168,7 @@ static int reconfig_codec(struct hda_codec *codec)
168 if (err < 0) 168 if (err < 0)
169 return err; 169 return err;
170 /* rebuild PCMs */ 170 /* rebuild PCMs */
171 err = snd_hda_build_pcms(codec->bus); 171 err = snd_hda_codec_build_pcms(codec);
172 if (err < 0) 172 if (err < 0)
173 return err; 173 return err;
174 /* rebuild mixers */ 174 /* rebuild mixers */