blob: d326c1bbeddea35c1b9154cdca751e50c080dcf8 [file] [log] [blame]
#include "aai.h"
#include "aai_hw.h"
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
int aai_pcms_probe(struct card_data_t *aai)
{
int err = 0;
int ipcm;
struct aai_device_t *chan;
/* alloc pcms table */
aai->pcms = kmalloc(aai->chans_nb * sizeof(struct snd_pcm *),
GFP_KERNEL);
if (!aai->pcms) {
err = -ENOMEM;
goto exit;
}
for (ipcm = 0; ipcm < aai->chans_nb; ipcm++) {
chan = &aai->chans[ipcm];
chan->driver_data = aai;
err = snd_pcm_new(aai->card,
chan->name,
ipcm,
((chan->direction&AAI_TX) == AAI_TX),
((chan->direction&AAI_RX) == AAI_RX),
&(aai->pcms[ipcm]));
if (err < 0) {
dev_err(aai->dev, "%s: %s (%d) init failed\n",
__func__, chan->name, ipcm);
goto exit;
}
aai->pcms[ipcm]->private_data = chan;
aai->pcms[ipcm]->info_flags = 0;
strncpy(aai->pcms[ipcm]->name, chan->name, DEV_NAME_LEN);
/* Set channel operators */
if (chan->direction & AAI_TX) {
snd_pcm_set_ops(aai->pcms[ipcm],
SNDRV_PCM_STREAM_PLAYBACK, chan->ops);
} else if (chan->direction & AAI_RX) {
snd_pcm_set_ops(aai->pcms[ipcm],
SNDRV_PCM_STREAM_CAPTURE, chan->ops);
} else {
dev_err(aai->dev, "%s init failed\n", chan->name);
err = -EINVAL;
goto exit;
}
/* Buffer memory preallocation */
err = snd_pcm_lib_preallocate_pages_for_all(aai->pcms[ipcm],
SNDRV_DMA_TYPE_DEV,
NULL,
64*1024,
64*1024);
if (err) {
dev_err(aai->dev, "%s: alsa memory preallocation "
"failed\n", __func__);
err = -EINVAL;
goto exit;
}
}
exit:
return err;
}
int aai_pcms_init(struct card_data_t *aai)
{
int err = 0;
int ipcm;
struct aai_device_t *chan;
aai->fifo_address = 0;
aai->fifo_tx = 0;
aai->fifo_rx = 0;
for (ipcm = 0; ipcm < aai->chans_nb; ipcm++) {
chan = &aai->chans[ipcm];
chan->ipcm = ipcm;
err = aai_hw_pcm_init(aai, chan);
if (err)
goto exit;
}
exit:
return err;
}
struct snd_card *aai_alsa_probe(struct platform_device *pdev)
{
int err;
struct snd_card *card = NULL;
struct card_data_t *aai;
int dev = pdev->id;
/* Create ALSA soundcard */
err = snd_card_create(index[dev], id[dev], THIS_MODULE,
sizeof(struct card_data_t), &card);
if (err < 0) {
dev_err(&pdev->dev, "card creation failed\n");
card = NULL;
goto exit;
}
aai = card->private_data;
aai->card = card;
aai->dev = &pdev->dev;
aai->pdata = dev_get_platdata(&pdev->dev);
/* Call hardware specific card init */
err = aai_hw_init_card(aai, dev);
if (err) {
dev_err(&pdev->dev, "hw init failed with error %d\n", err);
goto __nodev;
}
err = aai_pcms_probe(aai);
if (err) {
dev_err(&pdev->dev, "pcm probe failed with error %d\n", err);
goto __nodev;
}
/* Set device & register card to ALSA system */
snd_card_set_dev(card, &pdev->dev);
err = snd_card_register(card);
if (err != 0) {
dev_err(&pdev->dev, "card registration failed with error %d\n",
err);
goto __nodev;
}
exit:
return card;
__nodev:
snd_card_free(card);
card = NULL;
return card;
}
int aai_alsa_remove(struct snd_card *card)
{
int ipcm;
struct card_data_t *aai;
if (!card)
goto exit;
aai = card->private_data;
for (ipcm = 0; ipcm < aai->chans_nb; ipcm++)
snd_pcm_lib_preallocate_free_for_all(aai->pcms[ipcm]);
snd_card_free(card);
exit:
return 0;
}