mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
ALSA: sscape: Add suspend and resume support
The SoundScape ISA driver has lacked suspend and resume callbacks since commit277e926c9b("[ALSA] sscape - Use platform_device"). A plain snd_wss resume is not sufficient for SoundScape. Resume also needs to restore the board-specific gate-array routing, and non-VIVO boards need to reinitialize the probe-time MIDI firmware and MIDI control state when the MPU-401 side was enabled during probe. That firmware reload can be handled in-kernel because commitacd4710091("ALSA: sscape: convert to firmware loader framework") moved the driver to request_firmware(). Add ISA and ISA-PnP PM callbacks, reconfigure the board on resume, reload the non-VIVO MIDI firmware, restore the MIDI state, and then resume the WSS codec. If MIDI firmware reload fails, keep the WSS resume path alive and leave MIDI unavailable instead of failing the whole device resume. Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260411-alsa-sscape-pm-v2-2-aeb5682e14b0@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
committed by
Takashi Iwai
parent
f312f8b598
commit
713e0f0111
@@ -144,6 +144,7 @@ struct soundscape {
|
||||
|
||||
unsigned char midi_vol;
|
||||
bool joystick;
|
||||
bool midi_enabled;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
@@ -1107,6 +1108,7 @@ static int create_sscape(struct snd_card *card)
|
||||
}
|
||||
|
||||
sscape->midi_vol = 0;
|
||||
sscape->midi_enabled = true;
|
||||
err = sscape_restore_midi_state(sscape);
|
||||
if (err < 0)
|
||||
dev_warn(card->dev,
|
||||
@@ -1118,6 +1120,77 @@ static int create_sscape(struct snd_card *card)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
* Reload the MIDI firmware and restore the saved MIDI state for
|
||||
* boards whose MPU-401 side was enabled during probe.
|
||||
*/
|
||||
static int sscape_resume_midi(struct snd_card *card)
|
||||
{
|
||||
struct soundscape *sscape = get_card_soundscape(card);
|
||||
int err, version;
|
||||
|
||||
if (!sscape->midi_enabled)
|
||||
return 0;
|
||||
|
||||
version = sscape_upload_bootblock(card);
|
||||
if (version < 0)
|
||||
return version;
|
||||
|
||||
err = sscape_upload_microcode(card, version);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
outb(0, sscape->io_base);
|
||||
|
||||
return sscape_restore_midi_state(sscape);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the WSS codec state before the SoundScape is suspended.
|
||||
*/
|
||||
static int snd_sscape_suspend_card(struct snd_card *card)
|
||||
{
|
||||
struct soundscape *sscape = get_card_soundscape(card);
|
||||
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
||||
sscape->chip->suspend(sscape->chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the board-specific state before resuming the WSS codec.
|
||||
*/
|
||||
static int snd_sscape_resume_card(struct snd_card *card)
|
||||
{
|
||||
struct soundscape *sscape = get_card_soundscape(card);
|
||||
int err;
|
||||
|
||||
err = sscape_configure_board(sscape);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = sscape_resume_midi(card);
|
||||
if (err < 0)
|
||||
dev_warn(card->dev, "sscape: MIDI restore failed: %d\n", err);
|
||||
|
||||
sscape->chip->resume(sscape->chip);
|
||||
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_sscape_suspend(struct device *dev, unsigned int n,
|
||||
pm_message_t state)
|
||||
{
|
||||
return snd_sscape_suspend_card(dev_get_drvdata(dev));
|
||||
}
|
||||
|
||||
static int snd_sscape_resume(struct device *dev, unsigned int n)
|
||||
{
|
||||
return snd_sscape_resume_card(dev_get_drvdata(dev));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int snd_sscape_match(struct device *pdev, unsigned int i)
|
||||
{
|
||||
@@ -1174,6 +1247,10 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
|
||||
static struct isa_driver snd_sscape_driver = {
|
||||
.match = snd_sscape_match,
|
||||
.probe = snd_sscape_probe,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = snd_sscape_suspend,
|
||||
.resume = snd_sscape_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = DEV_NAME
|
||||
},
|
||||
@@ -1271,11 +1348,27 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int sscape_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
|
||||
{
|
||||
return snd_sscape_suspend_card(pnp_get_card_drvdata(pcard));
|
||||
}
|
||||
|
||||
static int sscape_pnp_resume(struct pnp_card_link *pcard)
|
||||
{
|
||||
return snd_sscape_resume_card(pnp_get_card_drvdata(pcard));
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pnp_card_driver sscape_pnpc_driver = {
|
||||
.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
|
||||
.name = "sscape",
|
||||
.id_table = sscape_pnpids,
|
||||
.probe = sscape_pnp_detect,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = sscape_pnp_suspend,
|
||||
.resume = sscape_pnp_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* CONFIG_PNP */
|
||||
|
||||
Reference in New Issue
Block a user