Skip to content

Commit

Permalink
ALSA: Echoaudio - Add suspend support #2
Browse files Browse the repository at this point in the history
This patch adds rearranges parts of the initialization code and adds
suspend and resume callbacks.

This patch adds suspend and resume callbacks.
It also rearranges parts of the initialization code so it can be
used in both the first initialization (when the module is loaded we
also have to load default settings) and the resume callback (where
we have to restore the previous settings).

Signed-off-by: Giuliano Pochini <pochini@shiny.it>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Giuliano Pochini authored and tiwai committed Feb 15, 2010
1 parent ad3499f commit 47b5d02
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 78 deletions.
153 changes: 138 additions & 15 deletions sound/pci/echoaudio/echoaudio.c
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)

spin_lock(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
DE_ACT(("pcm_trigger resume\n"));
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
DE_ACT(("pcm_trigger start\n"));
Expand All @@ -776,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
err = start_transport(chip, channelmask,
chip->pipe_cyclic_mask);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
DE_ACT(("pcm_trigger suspend\n"));
case SNDRV_PCM_TRIGGER_STOP:
DE_ACT(("pcm_trigger stop\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
Expand Down Expand Up @@ -1951,18 +1955,27 @@ static __devinit int snd_echo_create(struct snd_card *card,
return err;
pci_set_master(pci);

/* allocate a chip-specific data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
pci_disable_device(pci);
return -ENOMEM;
/* Allocate chip if needed */
if (!*rchip) {
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip) {
pci_disable_device(pci);
return -ENOMEM;
}
DE_INIT(("chip=%p\n", chip));
spin_lock_init(&chip->lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
atomic_set(&chip->opencount, 0);
mutex_init(&chip->mode_mutex);
chip->can_set_rate = 1;
} else {
/* If this was called from the resume function, chip is
* already allocated and it contains current card settings.
*/
chip = *rchip;
}
DE_INIT(("chip=%p\n", chip));

spin_lock_init(&chip->lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;

/* PCI resource allocation */
chip->dsp_registers_phys = pci_resource_start(pci, 0);
Expand Down Expand Up @@ -2002,7 +2015,9 @@ static __devinit int snd_echo_create(struct snd_card *card,
chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area;

err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err) {
if (err >= 0)
err = set_mixer_defaults(chip);
if (err < 0) {
DE_INIT(("init_hw err=%d\n", err));
snd_echo_free(chip);
return err;
Expand All @@ -2013,9 +2028,6 @@ static __devinit int snd_echo_create(struct snd_card *card,
snd_echo_free(chip);
return err;
}
atomic_set(&chip->opencount, 0);
mutex_init(&chip->mode_mutex);
chip->can_set_rate = 1;
*rchip = chip;
/* Init done ! */
return 0;
Expand Down Expand Up @@ -2048,6 +2060,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,

snd_card_set_dev(card, &pci->dev);

chip = NULL; /* Tells snd_echo_create to allocate chip */
if ((err = snd_echo_create(card, pci, &chip)) < 0) {
snd_card_free(card);
return err;
Expand Down Expand Up @@ -2187,6 +2200,112 @@ static int __devinit snd_echo_probe(struct pci_dev *pci,



#if defined(CONFIG_PM)

static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state)
{
struct echoaudio *chip = pci_get_drvdata(pci);

DE_INIT(("suspend start\n"));
snd_pcm_suspend_all(chip->analog_pcm);
snd_pcm_suspend_all(chip->digital_pcm);

#ifdef ECHOCARD_HAS_MIDI
/* This call can sleep */
if (chip->midi_out)
snd_echo_midi_output_trigger(chip->midi_out, 0);
#endif
spin_lock_irq(&chip->lock);
if (wait_handshake(chip)) {
spin_unlock_irq(&chip->lock);
return -EIO;
}
clear_handshake(chip);
if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) {
spin_unlock_irq(&chip->lock);
return -EIO;
}
spin_unlock_irq(&chip->lock);

chip->dsp_code = NULL;
free_irq(chip->irq, chip);
chip->irq = -1;
pci_save_state(pci);
pci_disable_device(pci);

DE_INIT(("suspend done\n"));
return 0;
}



static int snd_echo_resume(struct pci_dev *pci)
{
struct echoaudio *chip = pci_get_drvdata(pci);
struct comm_page *commpage, *commpage_bak;
u32 pipe_alloc_mask;
int err;

DE_INIT(("resume start\n"));
pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
commpage = chip->comm_page;
memcpy(commpage_bak, commpage, sizeof(struct comm_page));

err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err < 0) {
kfree(commpage_bak);
DE_INIT(("resume init_hw err=%d\n", err));
snd_echo_free(chip);
return err;
}
DE_INIT(("resume init OK\n"));

/* Temporarily set chip->pipe_alloc_mask=0 otherwise
* restore_dsp_settings() fails.
*/
pipe_alloc_mask = chip->pipe_alloc_mask;
chip->pipe_alloc_mask = 0;
err = restore_dsp_rettings(chip);
chip->pipe_alloc_mask = pipe_alloc_mask;
if (err < 0) {
kfree(commpage_bak);
return err;
}
DE_INIT(("resume restore OK\n"));

memcpy(&commpage->audio_format, &commpage_bak->audio_format,
sizeof(commpage->audio_format));
memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr,
sizeof(commpage->sglist_addr));
memcpy(&commpage->midi_output, &commpage_bak->midi_output,
sizeof(commpage->midi_output));
kfree(commpage_bak);

if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED,
ECHOCARD_NAME, chip)) {
snd_echo_free(chip);
snd_printk(KERN_ERR "cannot grab irq\n");
return -EBUSY;
}
chip->irq = pci->irq;
DE_INIT(("resume irq=%d\n", chip->irq));

#ifdef ECHOCARD_HAS_MIDI
if (chip->midi_input_enabled)
enable_midi_input(chip, TRUE);
if (chip->midi_out)
snd_echo_midi_output_trigger(chip->midi_out, 1);
#endif

DE_INIT(("resume done\n"));
return 0;
}

#endif /* CONFIG_PM */



static void __devexit snd_echo_remove(struct pci_dev *pci)
{
struct echoaudio *chip;
Expand All @@ -2209,6 +2328,10 @@ static struct pci_driver driver = {
.id_table = snd_echo_ids,
.probe = snd_echo_probe,
.remove = __devexit_p(snd_echo_remove),
#ifdef CONFIG_PM
.suspend = snd_echo_suspend,
.resume = snd_echo_resume,
#endif /* CONFIG_PM */
};


Expand Down
2 changes: 2 additions & 0 deletions sound/pci/echoaudio/echoaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,8 @@ static void free_firmware(const struct firmware *fw_entry);

#ifdef ECHOCARD_HAS_MIDI
static int enable_midi_input(struct echoaudio *chip, char enable);
static void snd_echo_midi_output_trigger(
struct snd_rawmidi_substream *substream, int up);
static int midi_service_irq(struct echoaudio *chip);
static int __devinit snd_echo_midi_create(struct snd_card *card,
struct echoaudio *chip);
Expand Down
Loading

0 comments on commit 47b5d02

Please sign in to comment.