Skip to content

Commit f312f8b

Browse files
CassivsGabriellistiwai
authored andcommitted
ALSA: sscape: Cache per-card resources for board reinitialization
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ássio Gabriel <cassiogabrielcontato@gmail.com> Link: https://patch.msgid.link/20260411-alsa-sscape-pm-v2-1-aeb5682e14b0@gmail.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 86aa1ea commit f312f8b

1 file changed

Lines changed: 139 additions & 95 deletions

File tree

sound/isa/sscape.c

Lines changed: 139 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,19 @@ enum card_type {
131131
struct soundscape {
132132
spinlock_t lock;
133133
unsigned io_base;
134+
unsigned long wss_base;
135+
int irq;
136+
int mpu_irq;
137+
int dma1;
138+
int dma2;
134139
int ic_type;
135140
enum card_type type;
136141
struct resource *io_res;
137142
struct resource *wss_res;
138143
struct snd_wss *chip;
139144

140145
unsigned char midi_vol;
146+
bool joystick;
141147
struct device *dev;
142148
};
143149

@@ -149,6 +155,21 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c)
149155
return (struct soundscape *) (c->private_data);
150156
}
151157

158+
/*
159+
* Store the resolved board settings in the per-card state so that
160+
* the same configuration can be replayed later if necessary.
161+
*/
162+
static void sscape_store_settings(struct soundscape *sscape, int dev)
163+
{
164+
sscape->io_base = port[dev];
165+
sscape->wss_base = wss_port[dev];
166+
sscape->irq = irq[dev];
167+
sscape->mpu_irq = mpu_irq[dev];
168+
sscape->dma1 = dma[dev];
169+
sscape->dma2 = dma2[dev];
170+
sscape->joystick = joystick[dev];
171+
}
172+
152173
/*
153174
* Allocates some kernel memory that we can use for DMA.
154175
* I think this means that the memory has to map to
@@ -263,34 +284,36 @@ static int host_read_ctrl_unsafe(unsigned io_base, unsigned timeout)
263284

264285
/*
265286
* Write to the SoundScape's host-mode control registers, but
266-
* leave any locking issues to the caller ...
287+
* leave any locking issues to the caller. Returns true if
288+
* the write succeeded.
267289
*/
268-
static inline int host_write_unsafe(unsigned io_base, unsigned char data)
290+
static inline bool host_write_unsafe(unsigned int io_base, unsigned char data)
269291
{
270292
if ((inb(HOST_CTRL_IO(io_base)) & TX_READY) != 0) {
271293
outb(data, HOST_DATA_IO(io_base));
272-
return 1;
294+
return true;
273295
}
274296

275-
return 0;
297+
return false;
276298
}
277299

278300
/*
279301
* Write to the SoundScape's host-mode control registers, performing
280302
* a limited amount of busy-waiting if the register isn't ready.
281-
* Also leaves all locking-issues to the caller ...
303+
* Also leaves all locking-issues to the caller. Returns true if
304+
* the write succeeded before timing out.
282305
*/
283-
static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data,
284-
unsigned timeout)
306+
static bool host_write_ctrl_unsafe(unsigned int io_base, unsigned char data,
307+
unsigned int timeout)
285308
{
286-
int err;
309+
bool written;
287310

288-
while (!(err = host_write_unsafe(io_base, data)) && (timeout != 0)) {
311+
while (!(written = host_write_unsafe(io_base, data)) && timeout != 0) {
289312
udelay(100);
290313
--timeout;
291314
} /* while */
292315

293-
return err;
316+
return written;
294317
}
295318

296319

@@ -560,6 +583,30 @@ static int sscape_upload_microcode(struct snd_card *card, int version)
560583
return err;
561584
}
562585

586+
/*
587+
* Restore the SoundScape's MIDI control state after the firmware
588+
* upload has made the host interface available again.
589+
*/
590+
static int sscape_restore_midi_state(struct soundscape *sscape)
591+
{
592+
bool success;
593+
594+
guard(spinlock_irqsave)(&sscape->lock);
595+
set_host_mode_unsafe(sscape->io_base);
596+
597+
success = host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100) &&
598+
host_write_ctrl_unsafe(sscape->io_base, sscape->midi_vol, 100) &&
599+
host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100) &&
600+
host_write_ctrl_unsafe(sscape->io_base, sscape->midi_vol, 100) &&
601+
host_write_ctrl_unsafe(sscape->io_base, CMD_SET_EXTMIDI, 100) &&
602+
host_write_ctrl_unsafe(sscape->io_base, 0, 100) &&
603+
host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
604+
605+
set_midi_mode_unsafe(sscape->io_base);
606+
607+
return success ? 0 : -EIO;
608+
}
609+
563610
/*
564611
* Mixer control for the SoundScape's MIDI device.
565612
*/
@@ -660,6 +707,59 @@ static unsigned get_irq_config(int sscape_type, int irq)
660707
return INVALID_IRQ;
661708
}
662709

710+
/*
711+
* Program the SoundScape's board-specific routing and enable the
712+
* codec path using the resolved IRQ, DMA and joystick settings.
713+
*/
714+
static int sscape_configure_board(struct soundscape *sscape)
715+
{
716+
unsigned int dma_cfg;
717+
unsigned int irq_cfg;
718+
unsigned int mpu_irq_cfg;
719+
int val;
720+
721+
irq_cfg = get_irq_config(sscape->type, sscape->irq);
722+
if (irq_cfg == INVALID_IRQ)
723+
return -ENXIO;
724+
725+
mpu_irq_cfg = get_irq_config(sscape->type, sscape->mpu_irq);
726+
if (mpu_irq_cfg == INVALID_IRQ)
727+
return -ENXIO;
728+
729+
scoped_guard(spinlock_irqsave, &sscape->lock) {
730+
if (sscape->ic_type == IC_OPUS)
731+
activate_ad1845_unsafe(sscape->io_base);
732+
733+
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
734+
sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
735+
736+
/*
737+
* Enable and configure the DMA channels ...
738+
*/
739+
sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
740+
dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
741+
sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
742+
sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
743+
744+
mpu_irq_cfg |= mpu_irq_cfg << 2;
745+
val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xf7;
746+
if (sscape->joystick)
747+
val |= 0x08;
748+
sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0xd0);
749+
sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG,
750+
0xf0 | mpu_irq_cfg);
751+
sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG,
752+
0x09 | DMA_8BIT |
753+
(sscape->dma1 << 4) | (irq_cfg << 1));
754+
/*
755+
* Enable the master IRQ ...
756+
*/
757+
sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
758+
}
759+
760+
return 0;
761+
}
762+
663763
/*
664764
* Perform certain arcane port-checks to see whether there
665765
* is a SoundScape board lurking behind the given ports.
@@ -890,56 +990,51 @@ static int create_ad1845(struct snd_card *card, unsigned port,
890990

891991
/*
892992
* Create an ALSA soundcard entry for the SoundScape, using
893-
* the given list of port, IRQ and DMA resources.
993+
* the resolved port, IRQ and DMA resources.
894994
*/
895-
static int create_sscape(int dev, struct snd_card *card)
995+
static int create_sscape(struct snd_card *card)
896996
{
897997
struct soundscape *sscape = get_card_soundscape(card);
898-
unsigned dma_cfg;
899-
unsigned irq_cfg;
900-
unsigned mpu_irq_cfg;
901998
struct resource *io_res;
902999
struct resource *wss_res;
9031000
int err;
904-
int val;
9051001
const char *name;
9061002

9071003
/*
9081004
* Grab IO ports that we will need to probe so that we
9091005
* can detect and control this hardware ...
9101006
*/
911-
io_res = devm_request_region(card->dev, port[dev], 8, "SoundScape");
1007+
io_res = devm_request_region(card->dev, sscape->io_base, 8, "SoundScape");
9121008
if (!io_res) {
9131009
dev_err(card->dev,
914-
"sscape: can't grab port 0x%lx\n", port[dev]);
1010+
"sscape: can't grab port 0x%x\n", sscape->io_base);
9151011
return -EBUSY;
9161012
}
9171013
wss_res = NULL;
9181014
if (sscape->type == SSCAPE_VIVO) {
919-
wss_res = devm_request_region(card->dev, wss_port[dev], 4,
1015+
wss_res = devm_request_region(card->dev, sscape->wss_base, 4,
9201016
"SoundScape");
9211017
if (!wss_res) {
9221018
dev_err(card->dev, "sscape: can't grab port 0x%lx\n",
923-
wss_port[dev]);
1019+
sscape->wss_base);
9241020
return -EBUSY;
9251021
}
9261022
}
9271023

9281024
/*
9291025
* Grab one DMA channel ...
9301026
*/
931-
err = snd_devm_request_dma(card->dev, dma[dev], "SoundScape");
1027+
err = snd_devm_request_dma(card->dev, sscape->dma1, "SoundScape");
9321028
if (err < 0) {
933-
dev_err(card->dev, "sscape: can't grab DMA %d\n", dma[dev]);
1029+
dev_err(card->dev, "sscape: can't grab DMA %d\n", sscape->dma1);
9341030
return err;
9351031
}
9361032

9371033
spin_lock_init(&sscape->lock);
9381034
sscape->io_res = io_res;
9391035
sscape->wss_res = wss_res;
940-
sscape->io_base = port[dev];
9411036

942-
if (!detect_sscape(sscape, wss_port[dev])) {
1037+
if (!detect_sscape(sscape, sscape->wss_base)) {
9431038
dev_err(card->dev, "sscape: hardware not detected at 0x%x\n",
9441039
sscape->io_base);
9451040
return -ENODEV;
@@ -964,66 +1059,28 @@ static int create_sscape(int dev, struct snd_card *card)
9641059
}
9651060

9661061
dev_info(card->dev, "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
967-
name, sscape->io_base, irq[dev], dma[dev]);
968-
969-
/*
970-
* Check that the user didn't pass us garbage data ...
971-
*/
972-
irq_cfg = get_irq_config(sscape->type, irq[dev]);
973-
if (irq_cfg == INVALID_IRQ) {
974-
dev_err(card->dev, "sscape: Invalid IRQ %d\n", irq[dev]);
975-
return -ENXIO;
976-
}
977-
978-
mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
979-
if (mpu_irq_cfg == INVALID_IRQ) {
980-
dev_err(card->dev, "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
981-
return -ENXIO;
982-
}
1062+
name, sscape->io_base, sscape->irq, sscape->dma1);
9831063

9841064
/*
9851065
* Tell the on-board devices where their resources are (I think -
9861066
* I can't be sure without a datasheet ... So many magic values!)
9871067
*/
988-
scoped_guard(spinlock_irqsave, &sscape->lock) {
989-
990-
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
991-
sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
992-
993-
/*
994-
* Enable and configure the DMA channels ...
995-
*/
996-
sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
997-
dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
998-
sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
999-
sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
1000-
1001-
mpu_irq_cfg |= mpu_irq_cfg << 2;
1002-
val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7;
1003-
if (joystick[dev])
1004-
val |= 8;
1005-
sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10);
1006-
sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
1007-
sscape_write_unsafe(sscape->io_base,
1008-
GA_CDCFG_REG, 0x09 | DMA_8BIT
1009-
| (dma[dev] << 4) | (irq_cfg << 1));
1010-
/*
1011-
* Enable the master IRQ ...
1012-
*/
1013-
sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80);
1014-
1068+
err = sscape_configure_board(sscape);
1069+
if (err < 0) {
1070+
dev_err(card->dev, "sscape: Invalid IRQ configuration\n");
1071+
return err;
10151072
}
10161073

10171074
/*
10181075
* We have now enabled the codec chip, and so we should
10191076
* detect the AD1845 device ...
10201077
*/
1021-
err = create_ad1845(card, wss_port[dev], irq[dev],
1022-
dma[dev], dma2[dev]);
1078+
err = create_ad1845(card, sscape->wss_base, sscape->irq,
1079+
sscape->dma1, sscape->dma2);
10231080
if (err < 0) {
10241081
dev_err(card->dev,
10251082
"sscape: No AD1845 device at 0x%lx, IRQ %d\n",
1026-
wss_port[dev], irq[dev]);
1083+
sscape->wss_base, sscape->irq);
10271084
return err;
10281085
}
10291086
strscpy(card->driver, "SoundScape");
@@ -1040,35 +1097,21 @@ static int create_sscape(int dev, struct snd_card *card)
10401097
err = sscape_upload_microcode(card, err);
10411098

10421099
if (err == 0) {
1043-
err = create_mpu401(card, MIDI_DEVNUM, port[dev],
1044-
mpu_irq[dev]);
1100+
err = create_mpu401(card, MIDI_DEVNUM, sscape->io_base,
1101+
sscape->mpu_irq);
10451102
if (err < 0) {
10461103
dev_err(card->dev,
10471104
"sscape: Failed to create MPU-401 device at 0x%lx\n",
1048-
port[dev]);
1105+
(unsigned long)sscape->io_base);
10491106
return err;
10501107
}
10511108

1052-
/*
1053-
* Initialize mixer
1054-
*/
1055-
guard(spinlock_irqsave)(&sscape->lock);
10561109
sscape->midi_vol = 0;
1057-
host_write_ctrl_unsafe(sscape->io_base,
1058-
CMD_SET_MIDI_VOL, 100);
1059-
host_write_ctrl_unsafe(sscape->io_base,
1060-
sscape->midi_vol, 100);
1061-
host_write_ctrl_unsafe(sscape->io_base,
1062-
CMD_XXX_MIDI_VOL, 100);
1063-
host_write_ctrl_unsafe(sscape->io_base,
1064-
sscape->midi_vol, 100);
1065-
host_write_ctrl_unsafe(sscape->io_base,
1066-
CMD_SET_EXTMIDI, 100);
1067-
host_write_ctrl_unsafe(sscape->io_base,
1068-
0, 100);
1069-
host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100);
1070-
1071-
set_midi_mode_unsafe(sscape->io_base);
1110+
err = sscape_restore_midi_state(sscape);
1111+
if (err < 0)
1112+
dev_warn(card->dev,
1113+
"sscape: MIDI init incomplete: %d\n",
1114+
err);
10721115
}
10731116
}
10741117

@@ -1111,8 +1154,9 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
11111154
sscape->type = SSCAPE;
11121155

11131156
dma[dev] &= 0x03;
1157+
sscape_store_settings(sscape, dev);
11141158

1115-
ret = create_sscape(dev, card);
1159+
ret = create_sscape(card);
11161160
if (ret < 0)
11171161
return ret;
11181162

@@ -1130,7 +1174,6 @@ static int snd_sscape_probe(struct device *pdev, unsigned int dev)
11301174
static struct isa_driver snd_sscape_driver = {
11311175
.match = snd_sscape_match,
11321176
.probe = snd_sscape_probe,
1133-
/* FIXME: suspend/resume */
11341177
.driver = {
11351178
.name = DEV_NAME
11361179
},
@@ -1211,8 +1254,9 @@ static int sscape_pnp_detect(struct pnp_card_link *pcard,
12111254
wss_port[idx] = pnp_port_start(dev, 1);
12121255
dma2[idx] = pnp_dma(dev, 1);
12131256
}
1257+
sscape_store_settings(sscape, idx);
12141258

1215-
ret = create_sscape(idx, card);
1259+
ret = create_sscape(card);
12161260
if (ret < 0)
12171261
return ret;
12181262

0 commit comments

Comments
 (0)