aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-07-30 09:01:44 -0400
committerTakashi Iwai <tiwai@suse.de>2008-10-12 20:42:58 -0400
commit176d5335fe66f379a339b0ab99cc7566e90ff1a9 (patch)
tree00f294bebf1270f65fe527141d3e6c1f440bba36 /sound/pci/hda
parent687cb98e893f492932abb3e92660d7d828bd44fb (diff)
ALSA: hda - Add infrastructure for dynamic stream allocation
Added the infrastructure for dynamic stream allocation on HD-audio. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c74
-rw-r--r--sound/pci/hda/hda_codec.h5
-rw-r--r--sound/pci/hda/hda_intel.c121
3 files changed, 105 insertions, 95 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 6447754ae56e..19b4530e3baf 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2262,6 +2262,28 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
2262 return 0; 2262 return 0;
2263} 2263}
2264 2264
2265/*
2266 * attach a new PCM stream
2267 */
2268static int __devinit
2269snd_hda_attach_pcm(struct hda_codec *codec, struct hda_pcm *pcm)
2270{
2271 struct hda_pcm_stream *info;
2272 int stream, err;
2273
2274 if (!pcm->name)
2275 return -EINVAL;
2276 for (stream = 0; stream < 2; stream++) {
2277 info = &pcm->stream[stream];
2278 if (info->substreams) {
2279 err = set_pcm_default_values(codec, info);
2280 if (err < 0)
2281 return err;
2282 }
2283 }
2284 return codec->bus->ops.attach_pcm(codec, pcm);
2285}
2286
2265/** 2287/**
2266 * snd_hda_build_pcms - build PCM information 2288 * snd_hda_build_pcms - build PCM information
2267 * @bus: the BUS 2289 * @bus: the BUS
@@ -2290,10 +2312,24 @@ static int __devinit set_pcm_default_values(struct hda_codec *codec,
2290 */ 2312 */
2291int __devinit snd_hda_build_pcms(struct hda_bus *bus) 2313int __devinit snd_hda_build_pcms(struct hda_bus *bus)
2292{ 2314{
2315 static const char *dev_name[HDA_PCM_NTYPES] = {
2316 "Audio", "SPDIF", "HDMI", "Modem"
2317 };
2318 /* starting device index for each PCM type */
2319 static int dev_idx[HDA_PCM_NTYPES] = {
2320 [HDA_PCM_TYPE_AUDIO] = 0,
2321 [HDA_PCM_TYPE_SPDIF] = 1,
2322 [HDA_PCM_TYPE_HDMI] = 3,
2323 [HDA_PCM_TYPE_MODEM] = 6
2324 };
2325 /* normal audio device indices; not linear to keep compatibility */
2326 static int audio_idx[4] = { 0, 2, 4, 5 };
2293 struct hda_codec *codec; 2327 struct hda_codec *codec;
2328 int num_devs[HDA_PCM_NTYPES];
2294 2329
2330 memset(num_devs, 0, sizeof(num_devs));
2295 list_for_each_entry(codec, &bus->codec_list, list) { 2331 list_for_each_entry(codec, &bus->codec_list, list) {
2296 unsigned int pcm, s; 2332 unsigned int pcm;
2297 int err; 2333 int err;
2298 if (!codec->patch_ops.build_pcms) 2334 if (!codec->patch_ops.build_pcms)
2299 continue; 2335 continue;
@@ -2301,15 +2337,37 @@ int __devinit snd_hda_build_pcms(struct hda_bus *bus)
2301 if (err < 0) 2337 if (err < 0)
2302 return err; 2338 return err;
2303 for (pcm = 0; pcm < codec->num_pcms; pcm++) { 2339 for (pcm = 0; pcm < codec->num_pcms; pcm++) {
2304 for (s = 0; s < 2; s++) { 2340 struct hda_pcm *cpcm = &codec->pcm_info[pcm];
2305 struct hda_pcm_stream *info; 2341 int type = cpcm->pcm_type;
2306 info = &codec->pcm_info[pcm].stream[s]; 2342 switch (type) {
2307 if (!info->substreams) 2343 case HDA_PCM_TYPE_AUDIO:
2344 if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
2345 snd_printk(KERN_WARNING
2346 "Too many audio devices\n");
2347 continue;
2348 }
2349 cpcm->device = audio_idx[num_devs[type]];
2350 break;
2351 case HDA_PCM_TYPE_SPDIF:
2352 case HDA_PCM_TYPE_HDMI:
2353 case HDA_PCM_TYPE_MODEM:
2354 if (num_devs[type]) {
2355 snd_printk(KERN_WARNING
2356 "%s already defined\n",
2357 dev_name[type]);
2308 continue; 2358 continue;
2309 err = set_pcm_default_values(codec, info); 2359 }
2310 if (err < 0) 2360 cpcm->device = dev_idx[type];
2311 return err; 2361 break;
2362 default:
2363 snd_printk(KERN_WARNING
2364 "Invalid PCM type %d\n", type);
2365 continue;
2312 } 2366 }
2367 num_devs[type]++;
2368 err = snd_hda_attach_pcm(codec, cpcm);
2369 if (err < 0)
2370 return err;
2313 } 2371 }
2314 } 2372 }
2315 return 0; 2373 return 0;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 60468f562400..70e8fa09273d 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -542,6 +542,8 @@ struct hda_bus_ops {
542 unsigned int (*get_response)(struct hda_codec *codec); 542 unsigned int (*get_response)(struct hda_codec *codec);
543 /* free the private data */ 543 /* free the private data */
544 void (*private_free)(struct hda_bus *); 544 void (*private_free)(struct hda_bus *);
545 /* attach a PCM stream */
546 int (*attach_pcm)(struct hda_codec *codec, struct hda_pcm *pcm);
545#ifdef CONFIG_SND_HDA_POWER_SAVE 547#ifdef CONFIG_SND_HDA_POWER_SAVE
546 /* notify power-up/down from codec to controller */ 548 /* notify power-up/down from codec to controller */
547 void (*pm_notify)(struct hda_codec *codec); 549 void (*pm_notify)(struct hda_codec *codec);
@@ -680,7 +682,8 @@ struct hda_pcm {
680 char *name; 682 char *name;
681 struct hda_pcm_stream stream[2]; 683 struct hda_pcm_stream stream[2];
682 unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */ 684 unsigned int pcm_type; /* HDA_PCM_TYPE_XXX */
683 int device; /* assigned device number */ 685 int device; /* device number to assign */
686 struct snd_pcm *pcm; /* assigned PCM instance */
684}; 687};
685 688
686/* codec information */ 689/* codec information */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 9f316c1b2790..7b0abf08a583 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
1180 return 0; 1180 return 0;
1181} 1181}
1182 1182
1183static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm);
1183 1184
1184/* 1185/*
1185 * Codec initialization 1186 * Codec initialization
@@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
1212 bus_temp.pci = chip->pci; 1213 bus_temp.pci = chip->pci;
1213 bus_temp.ops.command = azx_send_cmd; 1214 bus_temp.ops.command = azx_send_cmd;
1214 bus_temp.ops.get_response = azx_get_response; 1215 bus_temp.ops.get_response = azx_get_response;
1216 bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
1215#ifdef CONFIG_SND_HDA_POWER_SAVE 1217#ifdef CONFIG_SND_HDA_POWER_SAVE
1216 bus_temp.ops.pm_notify = azx_power_notify; 1218 bus_temp.ops.pm_notify = azx_power_notify;
1217#endif 1219#endif
@@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = {
1718 1720
1719static void azx_pcm_free(struct snd_pcm *pcm) 1721static void azx_pcm_free(struct snd_pcm *pcm)
1720{ 1722{
1721 kfree(pcm->private_data); 1723 struct azx_pcm *apcm = pcm->private_data;
1724 if (apcm) {
1725 apcm->chip->pcm[pcm->device] = NULL;
1726 kfree(apcm);
1727 }
1722} 1728}
1723 1729
1724static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec, 1730static int
1725 struct hda_pcm *cpcm) 1731azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm)
1726{ 1732{
1727 int err; 1733 struct azx *chip = codec->bus->private_data;
1728 struct snd_pcm *pcm; 1734 struct snd_pcm *pcm;
1729 struct azx_pcm *apcm; 1735 struct azx_pcm *apcm;
1736 int pcm_dev = cpcm->device;
1737 int s, err;
1730 1738
1731 /* if no substreams are defined for both playback and capture, 1739 if (pcm_dev >= AZX_MAX_PCMS) {
1732 * it's just a placeholder. ignore it. 1740 snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
1733 */ 1741 pcm_dev);
1734 if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
1735 return 0;
1736
1737 if (snd_BUG_ON(!cpcm->name))
1738 return -EINVAL; 1742 return -EINVAL;
1739 1743 }
1740 err = snd_pcm_new(chip->card, cpcm->name, cpcm->device, 1744 if (chip->pcm[pcm_dev]) {
1741 cpcm->stream[0].substreams, 1745 snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
1742 cpcm->stream[1].substreams, 1746 return -EBUSY;
1747 }
1748 err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
1749 cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
1750 cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
1743 &pcm); 1751 &pcm);
1744 if (err < 0) 1752 if (err < 0)
1745 return err; 1753 return err;
1746 strcpy(pcm->name, cpcm->name); 1754 strcpy(pcm->name, cpcm->name);
1747 apcm = kmalloc(sizeof(*apcm), GFP_KERNEL); 1755 apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
1748 if (apcm == NULL) 1756 if (apcm == NULL)
1749 return -ENOMEM; 1757 return -ENOMEM;
1750 apcm->chip = chip; 1758 apcm->chip = chip;
1751 apcm->codec = codec; 1759 apcm->codec = codec;
1752 apcm->hinfo[0] = &cpcm->stream[0];
1753 apcm->hinfo[1] = &cpcm->stream[1];
1754 pcm->private_data = apcm; 1760 pcm->private_data = apcm;
1755 pcm->private_free = azx_pcm_free; 1761 pcm->private_free = azx_pcm_free;
1756 if (cpcm->stream[0].substreams) 1762 if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
1757 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops); 1763 pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
1758 if (cpcm->stream[1].substreams) 1764 chip->pcm[pcm_dev] = pcm;
1759 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops); 1765 cpcm->pcm = pcm;
1766 for (s = 0; s < 2; s++) {
1767 apcm->hinfo[s] = &cpcm->stream[s];
1768 if (cpcm->stream[s].substreams)
1769 snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
1770 }
1771 /* buffer pre-allocation */
1760 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, 1772 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
1761 snd_dma_pci_data(chip->pci), 1773 snd_dma_pci_data(chip->pci),
1762 1024 * 64, 32 * 1024 * 1024); 1774 1024 * 64, 32 * 1024 * 1024);
1763 chip->pcm[cpcm->device] = pcm;
1764 return 0;
1765}
1766
1767static int __devinit azx_pcm_create(struct azx *chip)
1768{
1769 static const char *dev_name[HDA_PCM_NTYPES] = {
1770 "Audio", "SPDIF", "HDMI", "Modem"
1771 };
1772 /* starting device index for each PCM type */
1773 static int dev_idx[HDA_PCM_NTYPES] = {
1774 [HDA_PCM_TYPE_AUDIO] = 0,
1775 [HDA_PCM_TYPE_SPDIF] = 1,
1776 [HDA_PCM_TYPE_HDMI] = 3,
1777 [HDA_PCM_TYPE_MODEM] = 6
1778 };
1779 /* normal audio device indices; not linear to keep compatibility */
1780 static int audio_idx[4] = { 0, 2, 4, 5 };
1781 struct hda_codec *codec;
1782 int c, err;
1783 int num_devs[HDA_PCM_NTYPES];
1784
1785 err = snd_hda_build_pcms(chip->bus);
1786 if (err < 0)
1787 return err;
1788
1789 /* create audio PCMs */
1790 memset(num_devs, 0, sizeof(num_devs));
1791 list_for_each_entry(codec, &chip->bus->codec_list, list) {
1792 for (c = 0; c < codec->num_pcms; c++) {
1793 struct hda_pcm *cpcm = &codec->pcm_info[c];
1794 int type = cpcm->pcm_type;
1795 switch (type) {
1796 case HDA_PCM_TYPE_AUDIO:
1797 if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
1798 snd_printk(KERN_WARNING
1799 "Too many audio devices\n");
1800 continue;
1801 }
1802 cpcm->device = audio_idx[num_devs[type]];
1803 break;
1804 case HDA_PCM_TYPE_SPDIF:
1805 case HDA_PCM_TYPE_HDMI:
1806 case HDA_PCM_TYPE_MODEM:
1807 if (num_devs[type]) {
1808 snd_printk(KERN_WARNING
1809 "%s already defined\n",
1810 dev_name[type]);
1811 continue;
1812 }
1813 cpcm->device = dev_idx[type];
1814 break;
1815 default:
1816 snd_printk(KERN_WARNING
1817 "Invalid PCM type %d\n", type);
1818 continue;
1819 }
1820 num_devs[type]++;
1821 err = create_codec_pcm(chip, codec, cpcm);
1822 if (err < 0)
1823 return err;
1824 }
1825 }
1826 return 0; 1775 return 0;
1827} 1776}
1828 1777
@@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
2324 } 2273 }
2325 2274
2326 /* create PCM streams */ 2275 /* create PCM streams */
2327 err = azx_pcm_create(chip); 2276 err = snd_hda_build_pcms(chip->bus);
2328 if (err < 0) { 2277 if (err < 0) {
2329 snd_card_free(card); 2278 snd_card_free(card);
2330 return err; 2279 return err;