From nobody Mon Jun 15 15:07:43 2026 Received: from mail-dy1-f182.google.com (mail-dy1-f182.google.com [74.125.82.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A0BFF313283 for ; Sat, 11 Apr 2026 18:14:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775931296; cv=none; b=dq2+MPJXZ1KpCyMmYOnC4IHARAOOt8eGKkBuqyY6vSnTa0iAVk8XePMjDBRYJhYjUVwVPsNji4qcOMQIjx5lEy4RxtXtERX1rPcjleyYNFExskWciLkJu9M4MF0dwCTdpin6p6ac9kw5AsrKOHqM3PdJFw1JT4A8SumIgjlRchg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775931296; c=relaxed/simple; bh=lV9oovNP9pKxjlOzlOINWgSLUHMo/ci/wO3ZZavQpT8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fvvXQUzicNY6fBwtAxHIcRJQBJABAUAR3E6Hzx7gKA2uPRBqyGmsasQcG7O/hqRzh61BVRphOGdjgFfr0YtM50tPjVnxjUU3ETjHAihq+rMDjWe+/O4zaO714HCy+xEna5vQCs1Ja44585Cfombq2COM0hVontXWyEpSKQNIeZo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=hTAsMCp1; arc=none smtp.client-ip=74.125.82.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="hTAsMCp1" Received: by mail-dy1-f182.google.com with SMTP id 5a478bee46e88-2ba895adfeaso3036963eec.0 for ; Sat, 11 Apr 2026 11:14:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775931294; x=1776536094; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=2GmaA49yrbng+hcMbAK2cH3O+g/aOT7/qG6c1BDz7SI=; b=hTAsMCp1AV4XkbkqXUCwVH0i7OGJJJHP/dIW1hk1H/X9p5MtQa4QF6Ihb+OK+DDk62 vpJDpC+CFb+uMwf9B0oLYDj3OzfA0iueyeOA0otylLlpA9dILeD+OBF8nPjfZCLer+vB zCcxGsgt3V0O2eJJ8rGgWIwjOB2bBd4xBAesEsTPAMMNvXQknXGhziMUVSjHrjhs3nyZ +BkiM/0hVHJ3E+T+s5HyEQ+3BtURL0UjlnReXx0QIvgyokrCRnmWLBEd4SAMP5a1d1oC hPGkgBAbNHrS5VBOv9QyF7VHe+3bhnVd+TAO12aTmQhX92wmTBU0Vhce/mddpWyrbLsu ToJw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775931294; x=1776536094; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=2GmaA49yrbng+hcMbAK2cH3O+g/aOT7/qG6c1BDz7SI=; b=o9iXldj7vBvVOLnHObNcOeqGhbVW6qLPUcQXpL8aIxCxLU/DtSKcbP2kyMgihA+aj6 jJqINu9occ4WRzDjkyOlnCEpi26sI9aPiREv4NadXrBDK8N0cZ4RxKTRUajJD/eyIvPg WkW2EgUi6/yxV++Rby5hstTHiwKi967le7VPH4HhW62gLgRH4XQPbUOAjLMI9NV9L93G mW/IKGCy8gOgdV4XS5PyrbnEEuFfRPpIB459M2cnNsQPEi8P7dHwdvXZpUd9dOzFjrPd M+ClK6eTAoWo8krbVY3/yCFQmPdCSUgs3Qhrbq91gSEcIkPjpqY/hAAM0MK6hFRWOF6W x3PQ== X-Forwarded-Encrypted: i=1; AFNElJ8tbDFTG1Uix9I9Qss0M7T3zNL6kgSNGrssoHlA6zSczTJK6zM7YvXHT3xfvPaHPODPLI6fW33PZ4Nj9Ys=@vger.kernel.org X-Gm-Message-State: AOJu0YwWz7+MAzm2rn4fiWrrGHYiz6W+rioEkafcDfM+/R4ZJj8bmun2 2J+ZLIagK31Zm/rAK/PtdMiis8xdLs+OoDc0rERlYMXDuTn6fO6KoBWj X-Gm-Gg: AeBDiesuT+jmk/C8l04E+J0v419qwDL5s6eOWtxrFeH+PUo4wY7VnQ+tlvOssUXMKjg 6nevVsfR8aLzA1NPdH6NC3riJlWy+ooAKYN8T7SFDYPuEvpn3YnOAuROILfxOvBMsTA6lAW/cc9 zVsn2OjFyGttzAsXE7oLw5EujMHsNma7K7sQ9on+jjMGTyXjp7TODzOy9P0DoYcmUnbP+k1gwZk wudaABb954eVy0PnXP4yl9ulH9e/5Qar2A2VhxDe1U0+IC0pPIgdzPn6pRf1sfMFEo4RLtRqqzd GdcTbNm4WjpO0KKTdMw9XagObu7fZdYk9C0dj5AWp8VWkmniq/6ZhqDbehPRWUcPWHPeqvrjEMk l/2M+uQG6qUibhTApC5oIqxRpDsdBMsPvWyP7fKrpsglsZIi51WygUxiATW523/gHJGw4bNVYw7 klemhT5pagU15Zu5Ny7mBRm2HuZClyo0tkchUsqrKXSmunJqIfQ3wAFMzzlPv3cFCNbompls1WE kY8 X-Received: by 2002:a05:693c:6095:b0:2d8:2bbe:2d8d with SMTP id 5a478bee46e88-2d82bbe55a9mr96816eec.19.1775931293742; Sat, 11 Apr 2026 11:14:53 -0700 (PDT) Received: from [192.168.1.18] (177-4-160-195.user3p.v-tal.net.br. [177.4.160.195]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d55faa5257sm9627404eec.9.2026.04.11.11.14.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 11 Apr 2026 11:14:53 -0700 (PDT) From: =?utf-8?q?C=C3=A1ssio_Gabriel?= Date: Sat, 11 Apr 2026 15:14:40 -0300 Subject: [PATCH v2 1/2] ALSA: sscape: Cache per-card resources for board reinitialization Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260411-alsa-sscape-pm-v2-1-aeb5682e14b0@gmail.com> References: <20260411-alsa-sscape-pm-v2-0-aeb5682e14b0@gmail.com> In-Reply-To: <20260411-alsa-sscape-pm-v2-0-aeb5682e14b0@gmail.com> To: Takashi Iwai , Jaroslav Kysela Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, =?utf-8?q?C=C3=A1ssio_Gabriel?= X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=13441; i=cassiogabrielcontato@gmail.com; h=from:subject:message-id; bh=lV9oovNP9pKxjlOzlOINWgSLUHMo/ci/wO3ZZavQpT8=; b=owGbwMvMwCV2IdZeKur/u2bG02pJDJm3+qerXJ+v+eDI/WffClr4byYXqpTcKdr0JmZRMu+BS j7dzUe1O0pZGMS4GGTFFFlWJy2y3NP14Gp93AoPmDmsTCBDGLg4BWAiCzYw/NNwf5du+/iH04mD cv0ctxXijkuI79S/fVJx9sY7ITvUnAoY/udEH9j0drGwQd4hn7etXq/2/K5Orvn+fIZTjPhEKbW 5rQwA X-Developer-Key: i=cassiogabrielcontato@gmail.com; a=openpgp; fpr=AB62A239BC8AE0D57F5EA848D05D3F1A5AFFEE83 The SoundScape driver programs the gate-array directly from the global resource arrays during probe. That is sufficient for initial bring-up, but a PM resume path also needs the resolved per-card IRQ, DMA, MPU IRQ and joystick settings after probe has finished. Store the resolved resources in struct soundscape and move the board setup into a reusable helper. Also factor the MIDI state programming so the same sequence can be reused by a later PM resume path. This is preparatory work for suspend/resume support and is not intended to change runtime behaviour. Signed-off-by: C=C3=A1ssio Gabriel --- sound/isa/sscape.c | 234 +++++++++++++++++++++++++++++++------------------= ---- 1 file changed, 139 insertions(+), 95 deletions(-) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index a31ca75774a6..6e951b3c0080 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -131,6 +131,11 @@ enum card_type { struct soundscape { spinlock_t lock; unsigned io_base; + unsigned long wss_base; + int irq; + int mpu_irq; + int dma1; + int dma2; int ic_type; enum card_type type; struct resource *io_res; @@ -138,6 +143,7 @@ struct soundscape { struct snd_wss *chip; =20 unsigned char midi_vol; + bool joystick; struct device *dev; }; =20 @@ -149,6 +155,21 @@ static inline struct soundscape *get_card_soundscape(s= truct snd_card *c) return (struct soundscape *) (c->private_data); } =20 +/* + * Store the resolved board settings in the per-card state so that + * the same configuration can be replayed later if necessary. + */ +static void sscape_store_settings(struct soundscape *sscape, int dev) +{ + sscape->io_base =3D port[dev]; + sscape->wss_base =3D wss_port[dev]; + sscape->irq =3D irq[dev]; + sscape->mpu_irq =3D mpu_irq[dev]; + sscape->dma1 =3D dma[dev]; + sscape->dma2 =3D dma2[dev]; + sscape->joystick =3D joystick[dev]; +} + /* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to @@ -263,34 +284,36 @@ static int host_read_ctrl_unsafe(unsigned io_base, un= signed timeout) =20 /* * Write to the SoundScape's host-mode control registers, but - * leave any locking issues to the caller ... + * leave any locking issues to the caller. Returns true if + * the write succeeded. */ -static inline int host_write_unsafe(unsigned io_base, unsigned char data) +static inline bool host_write_unsafe(unsigned int io_base, unsigned char d= ata) { if ((inb(HOST_CTRL_IO(io_base)) & TX_READY) !=3D 0) { outb(data, HOST_DATA_IO(io_base)); - return 1; + return true; } =20 - return 0; + return false; } =20 /* * Write to the SoundScape's host-mode control registers, performing * a limited amount of busy-waiting if the register isn't ready. - * Also leaves all locking-issues to the caller ... + * Also leaves all locking-issues to the caller. Returns true if + * the write succeeded before timing out. */ -static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, - unsigned timeout) +static bool host_write_ctrl_unsafe(unsigned int io_base, unsigned char dat= a, + unsigned int timeout) { - int err; + bool written; =20 - while (!(err =3D host_write_unsafe(io_base, data)) && (timeout !=3D 0)) { + while (!(written =3D host_write_unsafe(io_base, data)) && timeout !=3D 0)= { udelay(100); --timeout; } /* while */ =20 - return err; + return written; } =20 =20 @@ -560,6 +583,30 @@ static int sscape_upload_microcode(struct snd_card *ca= rd, int version) return err; } =20 +/* + * Restore the SoundScape's MIDI control state after the firmware + * upload has made the host interface available again. + */ +static int sscape_restore_midi_state(struct soundscape *sscape) +{ + bool success; + + guard(spinlock_irqsave)(&sscape->lock); + set_host_mode_unsafe(sscape->io_base); + + success =3D host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100= ) && + host_write_ctrl_unsafe(sscape->io_base, sscape->midi_vol, 100) && + host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100) && + host_write_ctrl_unsafe(sscape->io_base, sscape->midi_vol, 100) && + host_write_ctrl_unsafe(sscape->io_base, CMD_SET_EXTMIDI, 100) && + host_write_ctrl_unsafe(sscape->io_base, 0, 100) && + host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); + + set_midi_mode_unsafe(sscape->io_base); + + return success ? 0 : -EIO; +} + /* * Mixer control for the SoundScape's MIDI device. */ @@ -660,6 +707,59 @@ static unsigned get_irq_config(int sscape_type, int ir= q) return INVALID_IRQ; } =20 +/* + * Program the SoundScape's board-specific routing and enable the + * codec path using the resolved IRQ, DMA and joystick settings. + */ +static int sscape_configure_board(struct soundscape *sscape) +{ + unsigned int dma_cfg; + unsigned int irq_cfg; + unsigned int mpu_irq_cfg; + int val; + + irq_cfg =3D get_irq_config(sscape->type, sscape->irq); + if (irq_cfg =3D=3D INVALID_IRQ) + return -ENXIO; + + mpu_irq_cfg =3D get_irq_config(sscape->type, sscape->mpu_irq); + if (mpu_irq_cfg =3D=3D INVALID_IRQ) + return -ENXIO; + + scoped_guard(spinlock_irqsave, &sscape->lock) { + if (sscape->ic_type =3D=3D IC_OPUS) + activate_ad1845_unsafe(sscape->io_base); + + sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); + sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); + + /* + * Enable and configure the DMA channels ... + */ + sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); + dma_cfg =3D (sscape->ic_type =3D=3D IC_OPUS ? 0x40 : 0x70); + sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); + sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); + + mpu_irq_cfg |=3D mpu_irq_cfg << 2; + val =3D sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xf7; + if (sscape->joystick) + val |=3D 0x08; + sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0xd0); + sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, + 0xf0 | mpu_irq_cfg); + sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG, + 0x09 | DMA_8BIT | + (sscape->dma1 << 4) | (irq_cfg << 1)); + /* + * Enable the master IRQ ... + */ + sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); + } + + return 0; +} + /* * Perform certain arcane port-checks to see whether there * is a SoundScape board lurking behind the given ports. @@ -890,37 +990,33 @@ static int create_ad1845(struct snd_card *card, unsig= ned port, =20 /* * Create an ALSA soundcard entry for the SoundScape, using - * the given list of port, IRQ and DMA resources. + * the resolved port, IRQ and DMA resources. */ -static int create_sscape(int dev, struct snd_card *card) +static int create_sscape(struct snd_card *card) { struct soundscape *sscape =3D get_card_soundscape(card); - unsigned dma_cfg; - unsigned irq_cfg; - unsigned mpu_irq_cfg; struct resource *io_res; struct resource *wss_res; int err; - int val; const char *name; =20 /* * Grab IO ports that we will need to probe so that we * can detect and control this hardware ... */ - io_res =3D devm_request_region(card->dev, port[dev], 8, "SoundScape"); + io_res =3D devm_request_region(card->dev, sscape->io_base, 8, "SoundScape= "); if (!io_res) { dev_err(card->dev, - "sscape: can't grab port 0x%lx\n", port[dev]); + "sscape: can't grab port 0x%x\n", sscape->io_base); return -EBUSY; } wss_res =3D NULL; if (sscape->type =3D=3D SSCAPE_VIVO) { - wss_res =3D devm_request_region(card->dev, wss_port[dev], 4, + wss_res =3D devm_request_region(card->dev, sscape->wss_base, 4, "SoundScape"); if (!wss_res) { dev_err(card->dev, "sscape: can't grab port 0x%lx\n", - wss_port[dev]); + sscape->wss_base); return -EBUSY; } } @@ -928,18 +1024,17 @@ static int create_sscape(int dev, struct snd_card *c= ard) /* * Grab one DMA channel ... */ - err =3D snd_devm_request_dma(card->dev, dma[dev], "SoundScape"); + err =3D snd_devm_request_dma(card->dev, sscape->dma1, "SoundScape"); if (err < 0) { - dev_err(card->dev, "sscape: can't grab DMA %d\n", dma[dev]); + dev_err(card->dev, "sscape: can't grab DMA %d\n", sscape->dma1); return err; } =20 spin_lock_init(&sscape->lock); sscape->io_res =3D io_res; sscape->wss_res =3D wss_res; - sscape->io_base =3D port[dev]; =20 - if (!detect_sscape(sscape, wss_port[dev])) { + if (!detect_sscape(sscape, sscape->wss_base)) { dev_err(card->dev, "sscape: hardware not detected at 0x%x\n", sscape->io_base); return -ENODEV; @@ -964,66 +1059,28 @@ static int create_sscape(int dev, struct snd_card *c= ard) } =20 dev_info(card->dev, "sscape: %s card detected at 0x%x, using IRQ %d, DMA = %d\n", - name, sscape->io_base, irq[dev], dma[dev]); - - /* - * Check that the user didn't pass us garbage data ... - */ - irq_cfg =3D get_irq_config(sscape->type, irq[dev]); - if (irq_cfg =3D=3D INVALID_IRQ) { - dev_err(card->dev, "sscape: Invalid IRQ %d\n", irq[dev]); - return -ENXIO; - } - - mpu_irq_cfg =3D get_irq_config(sscape->type, mpu_irq[dev]); - if (mpu_irq_cfg =3D=3D INVALID_IRQ) { - dev_err(card->dev, "sscape: Invalid IRQ %d\n", mpu_irq[dev]); - return -ENXIO; - } + name, sscape->io_base, sscape->irq, sscape->dma1); =20 /* * Tell the on-board devices where their resources are (I think - * I can't be sure without a datasheet ... So many magic values!) */ - scoped_guard(spinlock_irqsave, &sscape->lock) { - - sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); - sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); - - /* - * Enable and configure the DMA channels ... - */ - sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); - dma_cfg =3D (sscape->ic_type =3D=3D IC_OPUS ? 0x40 : 0x70); - sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); - sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); - - mpu_irq_cfg |=3D mpu_irq_cfg << 2; - val =3D sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; - if (joystick[dev]) - val |=3D 8; - sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); - sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); - sscape_write_unsafe(sscape->io_base, - GA_CDCFG_REG, 0x09 | DMA_8BIT - | (dma[dev] << 4) | (irq_cfg << 1)); - /* - * Enable the master IRQ ... - */ - sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); - + err =3D sscape_configure_board(sscape); + if (err < 0) { + dev_err(card->dev, "sscape: Invalid IRQ configuration\n"); + return err; } =20 /* * We have now enabled the codec chip, and so we should * detect the AD1845 device ... */ - err =3D create_ad1845(card, wss_port[dev], irq[dev], - dma[dev], dma2[dev]); + err =3D create_ad1845(card, sscape->wss_base, sscape->irq, + sscape->dma1, sscape->dma2); if (err < 0) { dev_err(card->dev, "sscape: No AD1845 device at 0x%lx, IRQ %d\n", - wss_port[dev], irq[dev]); + sscape->wss_base, sscape->irq); return err; } strscpy(card->driver, "SoundScape"); @@ -1040,35 +1097,21 @@ static int create_sscape(int dev, struct snd_card *= card) err =3D sscape_upload_microcode(card, err); =20 if (err =3D=3D 0) { - err =3D create_mpu401(card, MIDI_DEVNUM, port[dev], - mpu_irq[dev]); + err =3D create_mpu401(card, MIDI_DEVNUM, sscape->io_base, + sscape->mpu_irq); if (err < 0) { dev_err(card->dev, "sscape: Failed to create MPU-401 device at 0x%lx\n", - port[dev]); + (unsigned long)sscape->io_base); return err; } =20 - /* - * Initialize mixer - */ - guard(spinlock_irqsave)(&sscape->lock); sscape->midi_vol =3D 0; - host_write_ctrl_unsafe(sscape->io_base, - CMD_SET_MIDI_VOL, 100); - host_write_ctrl_unsafe(sscape->io_base, - sscape->midi_vol, 100); - host_write_ctrl_unsafe(sscape->io_base, - CMD_XXX_MIDI_VOL, 100); - host_write_ctrl_unsafe(sscape->io_base, - sscape->midi_vol, 100); - host_write_ctrl_unsafe(sscape->io_base, - CMD_SET_EXTMIDI, 100); - host_write_ctrl_unsafe(sscape->io_base, - 0, 100); - host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); - - set_midi_mode_unsafe(sscape->io_base); + err =3D sscape_restore_midi_state(sscape); + if (err < 0) + dev_warn(card->dev, + "sscape: MIDI init incomplete: %d\n", + err); } } =20 @@ -1111,8 +1154,9 @@ static int snd_sscape_probe(struct device *pdev, unsi= gned int dev) sscape->type =3D SSCAPE; =20 dma[dev] &=3D 0x03; + sscape_store_settings(sscape, dev); =20 - ret =3D create_sscape(dev, card); + ret =3D create_sscape(card); if (ret < 0) return ret; =20 @@ -1130,7 +1174,6 @@ static int snd_sscape_probe(struct device *pdev, unsi= gned int dev) static struct isa_driver snd_sscape_driver =3D { .match =3D snd_sscape_match, .probe =3D snd_sscape_probe, - /* FIXME: suspend/resume */ .driver =3D { .name =3D DEV_NAME }, @@ -1211,8 +1254,9 @@ static int sscape_pnp_detect(struct pnp_card_link *pc= ard, wss_port[idx] =3D pnp_port_start(dev, 1); dma2[idx] =3D pnp_dma(dev, 1); } + sscape_store_settings(sscape, idx); =20 - ret =3D create_sscape(idx, card); + ret =3D create_sscape(card); if (ret < 0) return ret; =20 --=20 2.53.0 From nobody Mon Jun 15 15:07:43 2026 Received: from mail-dy1-f182.google.com (mail-dy1-f182.google.com [74.125.82.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7B1A431195B for ; Sat, 11 Apr 2026 18:14:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775931298; cv=none; b=iKrCa2SJuhGspc0qHwhDHguEx6Mkj3ZP5RxXOyEDU5ToAllDJTfe6ed2BveTM+F5CgOUmsGZ52Z6aQlO6xtdo56M0PTV+Ws3id/Qg00VHTbtdMuzfp7N738wc2lyT0+2CdcVoHVMhiZGSiUUYpO/+9nzpdNXKWti0L24/8aADpY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775931298; c=relaxed/simple; bh=JFfoqwMVeT5YwC7Mj2h/2QwAUTtfU8oUhv1gKgOzqPs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=d3HzYWFw/iK/4zL+tkvGzrC0IxfQUWCFBCKgO6cuE0+vq6FlUG+oY/oMOnDlD1rECk3JagK/BaJBEjq8D5UHzohePWpHTVxBEFKCYw0znkPKCiE9pnoz6Diky/KLWVQJsl880s9fA0X+5dz/8IFUYOc9eSNpnluMHYQJL57Wid8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=O9K2Db7E; arc=none smtp.client-ip=74.125.82.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="O9K2Db7E" Received: by mail-dy1-f182.google.com with SMTP id 5a478bee46e88-2d52c7f92b1so2363806eec.0 for ; Sat, 11 Apr 2026 11:14:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775931297; x=1776536097; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=YyJvFj1J0DxahqFN0TQkOSw9GkLQZJBa6Fp8Qfm2mJs=; b=O9K2Db7EyPlEOUL/z5jvmPcQH9r0koDZUfCv5c7bjl55+83PD8+RaLW8YDPeh4KsgZ Cl13+Dys44d00e1Y92VE0rEC+YIfX+wMwF6dqg4a5U16eIFloHs5qouRuZQUIgGqz+QG 7uCmx3PnOMF5GzcoACIahv6e5EnP9YKHPUTrTW7Rjkn1ZVCM8MEaNkhXQFwVfYGCJhuq Uxr6N6baQq7mZMRU4V/wvqIGwyI0hvTawIHzG3AVDDDcl65RdcpVFRl54QOX6wDzwd9f /toqljw8I4Q3tKs3DByArox33rAS0ZLyze/PQUvrSv8Kgty3LKPYgbMTTKPGitvyvLrC Ml7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775931297; x=1776536097; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=YyJvFj1J0DxahqFN0TQkOSw9GkLQZJBa6Fp8Qfm2mJs=; b=PuCCAW3FEcSANjwbvm0tN0ZLao1AL2tPP+GuumphMRH4rGwVPgmOKGF2gOK+yiQZZy jypjAfTi/imfGdfiEcqwHsM4UQnqyYDBMSkknURp4By/oWiI4BG2Dm53+C3sR0ia+KeT G88X7nzv+rxceHaSFILedNXmLB43cFGq0euW0dI82klD7cOrAKjczZjt1ZENfcV6kLyE 19asMw5p10UmzJe1OUH+hLPKva2gvop/A78xZH/RhMn2RKInk9XGmQtrM3WXUm9Qc0vC dJ6r7fHpdU7YhH3do5EeAB1KBdee/La7kCFFXfYfIkJi3wluKwcqeCELdH81mHSpxGwm HS5A== X-Forwarded-Encrypted: i=1; AFNElJ8dGCuE5hL5cFHhCdbnZlhLZRYku5FYot57hgCLKXiIwMYWmYQWc00cixnCTzxzrTN2rONjaziBqt0SJrE=@vger.kernel.org X-Gm-Message-State: AOJu0YzTDahFQW8x0XBjBn1CppDhTizYU+2226J0Dcesb6QqT9AGt618 IR8t1skAGVm3U09rCWsX/aYPbzFcpRCxCS7ddWWeHqzFKSE6NTlp2Q/3e+XsKT2l X-Gm-Gg: AeBDietkjrvFINvdaf4MsAoCm7LTx48pgVZRAUulZR3MGg80avqT4mE3aqGEOwxJDmX cPLj3Nvp7xnhTETYWGKxF28DGE/kpYxf3trqihNTRt5/FtkfpDCz5/zJmOrpnlNb2MnANbsJ+j2 JU5IbQMaN2R3mEaFROUFCg8J6ZVnvlr9S52xCsTVaM1uGtgFYdrU9NYaFg15QoN1haxIMt8oM6O AmSUtLThaNE36NrmYKeN82SOJWoGBUgCVajBkPEy4r4LSbAM8HvKhYc7ZQ5f4j25dxay8PvafIE 7IsHXY4X1JMq6oPcptsE/yD+CgJ2769ltfSQHWnHxSONvQbEXYe0FBsf6q40jpuqmPOKNrsPje8 vNbR18C6vUXRmY3VNlKxNonvVFoWrNHO96d7SrS/MegEQe5bzUncJcNa4bgCkXVWYeQvzNn/Eac RLr+NWsjisjelE2Ni/eVkW9b+UBkL6aI3r5qHhTpuDSYNZOwmvgNT+efYiWo98ajICuLFg3oVIO tHE X-Received: by 2002:a05:7300:e207:b0:2c5:d833:a4fe with SMTP id 5a478bee46e88-2d5876a10f7mr4451864eec.10.1775931296585; Sat, 11 Apr 2026 11:14:56 -0700 (PDT) Received: from [192.168.1.18] (177-4-160-195.user3p.v-tal.net.br. [177.4.160.195]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2d55faa5257sm9627404eec.9.2026.04.11.11.14.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 11 Apr 2026 11:14:56 -0700 (PDT) From: =?utf-8?q?C=C3=A1ssio_Gabriel?= Date: Sat, 11 Apr 2026 15:14:41 -0300 Subject: [PATCH v2 2/2] ALSA: sscape: Add suspend and resume support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260411-alsa-sscape-pm-v2-2-aeb5682e14b0@gmail.com> References: <20260411-alsa-sscape-pm-v2-0-aeb5682e14b0@gmail.com> In-Reply-To: <20260411-alsa-sscape-pm-v2-0-aeb5682e14b0@gmail.com> To: Takashi Iwai , Jaroslav Kysela Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, =?utf-8?q?C=C3=A1ssio_Gabriel?= X-Mailer: b4 0.15.1 X-Developer-Signature: v=1; a=openpgp-sha256; l=4588; i=cassiogabrielcontato@gmail.com; h=from:subject:message-id; bh=JFfoqwMVeT5YwC7Mj2h/2QwAUTtfU8oUhv1gKgOzqPs=; b=owGbwMvMwCV2IdZeKur/u2bG02pJDJm3+qfvvnWexbbIayXnbR22ic9mxr0wknEJCv4w79Td0 OYbNjP+dZSyMIhxMciKKbKsTlpkuafrwdX6uBUeMHNYmUCGMHBxCsBEHroyMpyZXvboX+DWd8ee 9l4pb/wsE5bJcrrm4P21pnt+bxH9e2sVI8O575ciJzFmCvpVLlrwL91ptab2HZMHJ+2X/ZvDdp/ /2lIeAA== X-Developer-Key: i=cassiogabrielcontato@gmail.com; a=openpgp; fpr=AB62A239BC8AE0D57F5EA848D05D3F1A5AFFEE83 The SoundScape ISA driver has lacked suspend and resume callbacks since commit 277e926c9b27 ("[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 commit acd47100914b ("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=C3=A1ssio Gabriel --- sound/isa/sscape.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 93 insertions(+) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 6e951b3c0080..553ceb92d298 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -144,6 +144,7 @@ struct soundscape { =20 unsigned char midi_vol; bool joystick; + bool midi_enabled; struct device *dev; }; =20 @@ -1107,6 +1108,7 @@ static int create_sscape(struct snd_card *card) } =20 sscape->midi_vol =3D 0; + sscape->midi_enabled =3D true; err =3D 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; } =20 +#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 =3D get_card_soundscape(card); + int err, version; + + if (!sscape->midi_enabled) + return 0; + + version =3D sscape_upload_bootblock(card); + if (version < 0) + return version; + + err =3D 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 =3D 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 =3D get_card_soundscape(card); + int err; + + err =3D sscape_configure_board(sscape); + if (err < 0) + return err; + + err =3D 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 + =20 static int snd_sscape_match(struct device *pdev, unsigned int i) { @@ -1174,6 +1247,10 @@ static int snd_sscape_probe(struct device *pdev, uns= igned int dev) static struct isa_driver snd_sscape_driver =3D { .match =3D snd_sscape_match, .probe =3D snd_sscape_probe, +#ifdef CONFIG_PM + .suspend =3D snd_sscape_suspend, + .resume =3D snd_sscape_resume, +#endif .driver =3D { .name =3D DEV_NAME }, @@ -1271,11 +1348,27 @@ static int sscape_pnp_detect(struct pnp_card_link *= pcard, return 0; } =20 +#ifdef CONFIG_PM +static int sscape_pnp_suspend(struct pnp_card_link *pcard, pm_message_t st= ate) +{ + 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 =3D { .flags =3D PNP_DRIVER_RES_DO_NOT_CHANGE, .name =3D "sscape", .id_table =3D sscape_pnpids, .probe =3D sscape_pnp_detect, +#ifdef CONFIG_PM + .suspend =3D sscape_pnp_suspend, + .resume =3D sscape_pnp_resume, +#endif }; =20 #endif /* CONFIG_PNP */ --=20 2.53.0