|
@@ -1180,6 +1180,7 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm);
|
|
|
|
|
|
/*
|
|
|
* Codec initialization
|
|
@@ -1212,6 +1213,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model,
|
|
|
bus_temp.pci = chip->pci;
|
|
|
bus_temp.ops.command = azx_send_cmd;
|
|
|
bus_temp.ops.get_response = azx_get_response;
|
|
|
+ bus_temp.ops.attach_pcm = azx_attach_pcm_stream;
|
|
|
#ifdef CONFIG_SND_HDA_POWER_SAVE
|
|
|
bus_temp.ops.pm_notify = azx_power_notify;
|
|
|
#endif
|
|
@@ -1718,111 +1720,58 @@ static struct snd_pcm_ops azx_pcm_ops = {
|
|
|
|
|
|
static void azx_pcm_free(struct snd_pcm *pcm)
|
|
|
{
|
|
|
- kfree(pcm->private_data);
|
|
|
+ struct azx_pcm *apcm = pcm->private_data;
|
|
|
+ if (apcm) {
|
|
|
+ apcm->chip->pcm[pcm->device] = NULL;
|
|
|
+ kfree(apcm);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static int __devinit create_codec_pcm(struct azx *chip, struct hda_codec *codec,
|
|
|
- struct hda_pcm *cpcm)
|
|
|
+static int
|
|
|
+azx_attach_pcm_stream(struct hda_codec *codec, struct hda_pcm *cpcm)
|
|
|
{
|
|
|
- int err;
|
|
|
+ struct azx *chip = codec->bus->private_data;
|
|
|
struct snd_pcm *pcm;
|
|
|
struct azx_pcm *apcm;
|
|
|
+ int pcm_dev = cpcm->device;
|
|
|
+ int s, err;
|
|
|
|
|
|
- /* if no substreams are defined for both playback and capture,
|
|
|
- * it's just a placeholder. ignore it.
|
|
|
- */
|
|
|
- if (!cpcm->stream[0].substreams && !cpcm->stream[1].substreams)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (snd_BUG_ON(!cpcm->name))
|
|
|
+ if (pcm_dev >= AZX_MAX_PCMS) {
|
|
|
+ snd_printk(KERN_ERR SFX "Invalid PCM device number %d\n",
|
|
|
+ pcm_dev);
|
|
|
return -EINVAL;
|
|
|
-
|
|
|
- err = snd_pcm_new(chip->card, cpcm->name, cpcm->device,
|
|
|
- cpcm->stream[0].substreams,
|
|
|
- cpcm->stream[1].substreams,
|
|
|
+ }
|
|
|
+ if (chip->pcm[pcm_dev]) {
|
|
|
+ snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+ err = snd_pcm_new(chip->card, cpcm->name, pcm_dev,
|
|
|
+ cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams,
|
|
|
+ cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams,
|
|
|
&pcm);
|
|
|
if (err < 0)
|
|
|
return err;
|
|
|
strcpy(pcm->name, cpcm->name);
|
|
|
- apcm = kmalloc(sizeof(*apcm), GFP_KERNEL);
|
|
|
+ apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
|
|
|
if (apcm == NULL)
|
|
|
return -ENOMEM;
|
|
|
apcm->chip = chip;
|
|
|
apcm->codec = codec;
|
|
|
- apcm->hinfo[0] = &cpcm->stream[0];
|
|
|
- apcm->hinfo[1] = &cpcm->stream[1];
|
|
|
pcm->private_data = apcm;
|
|
|
pcm->private_free = azx_pcm_free;
|
|
|
- if (cpcm->stream[0].substreams)
|
|
|
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &azx_pcm_ops);
|
|
|
- if (cpcm->stream[1].substreams)
|
|
|
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &azx_pcm_ops);
|
|
|
+ if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM)
|
|
|
+ pcm->dev_class = SNDRV_PCM_CLASS_MODEM;
|
|
|
+ chip->pcm[pcm_dev] = pcm;
|
|
|
+ cpcm->pcm = pcm;
|
|
|
+ for (s = 0; s < 2; s++) {
|
|
|
+ apcm->hinfo[s] = &cpcm->stream[s];
|
|
|
+ if (cpcm->stream[s].substreams)
|
|
|
+ snd_pcm_set_ops(pcm, s, &azx_pcm_ops);
|
|
|
+ }
|
|
|
+ /* buffer pre-allocation */
|
|
|
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
|
|
|
snd_dma_pci_data(chip->pci),
|
|
|
1024 * 64, 32 * 1024 * 1024);
|
|
|
- chip->pcm[cpcm->device] = pcm;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int __devinit azx_pcm_create(struct azx *chip)
|
|
|
-{
|
|
|
- static const char *dev_name[HDA_PCM_NTYPES] = {
|
|
|
- "Audio", "SPDIF", "HDMI", "Modem"
|
|
|
- };
|
|
|
- /* starting device index for each PCM type */
|
|
|
- static int dev_idx[HDA_PCM_NTYPES] = {
|
|
|
- [HDA_PCM_TYPE_AUDIO] = 0,
|
|
|
- [HDA_PCM_TYPE_SPDIF] = 1,
|
|
|
- [HDA_PCM_TYPE_HDMI] = 3,
|
|
|
- [HDA_PCM_TYPE_MODEM] = 6
|
|
|
- };
|
|
|
- /* normal audio device indices; not linear to keep compatibility */
|
|
|
- static int audio_idx[4] = { 0, 2, 4, 5 };
|
|
|
- struct hda_codec *codec;
|
|
|
- int c, err;
|
|
|
- int num_devs[HDA_PCM_NTYPES];
|
|
|
-
|
|
|
- err = snd_hda_build_pcms(chip->bus);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
-
|
|
|
- /* create audio PCMs */
|
|
|
- memset(num_devs, 0, sizeof(num_devs));
|
|
|
- list_for_each_entry(codec, &chip->bus->codec_list, list) {
|
|
|
- for (c = 0; c < codec->num_pcms; c++) {
|
|
|
- struct hda_pcm *cpcm = &codec->pcm_info[c];
|
|
|
- int type = cpcm->pcm_type;
|
|
|
- switch (type) {
|
|
|
- case HDA_PCM_TYPE_AUDIO:
|
|
|
- if (num_devs[type] >= ARRAY_SIZE(audio_idx)) {
|
|
|
- snd_printk(KERN_WARNING
|
|
|
- "Too many audio devices\n");
|
|
|
- continue;
|
|
|
- }
|
|
|
- cpcm->device = audio_idx[num_devs[type]];
|
|
|
- break;
|
|
|
- case HDA_PCM_TYPE_SPDIF:
|
|
|
- case HDA_PCM_TYPE_HDMI:
|
|
|
- case HDA_PCM_TYPE_MODEM:
|
|
|
- if (num_devs[type]) {
|
|
|
- snd_printk(KERN_WARNING
|
|
|
- "%s already defined\n",
|
|
|
- dev_name[type]);
|
|
|
- continue;
|
|
|
- }
|
|
|
- cpcm->device = dev_idx[type];
|
|
|
- break;
|
|
|
- default:
|
|
|
- snd_printk(KERN_WARNING
|
|
|
- "Invalid PCM type %d\n", type);
|
|
|
- continue;
|
|
|
- }
|
|
|
- num_devs[type]++;
|
|
|
- err = create_codec_pcm(chip, codec, cpcm);
|
|
|
- if (err < 0)
|
|
|
- return err;
|
|
|
- }
|
|
|
- }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2324,7 +2273,7 @@ static int __devinit azx_probe(struct pci_dev *pci,
|
|
|
}
|
|
|
|
|
|
/* create PCM streams */
|
|
|
- err = azx_pcm_create(chip);
|
|
|
+ err = snd_hda_build_pcms(chip->bus);
|
|
|
if (err < 0) {
|
|
|
snd_card_free(card);
|
|
|
return err;
|