]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - sound/isa/sb/sb8.c
ALSA: sb: Allocate resources with device-managed APIs
[thirdparty/kernel/stable.git] / sound / isa / sb / sb8.c
CommitLineData
1a59d1b8 1// SPDX-License-Identifier: GPL-2.0-or-later
1da177e4
LT
2/*
3 * Driver for SoundBlaster 1.0/2.0/Pro soundcards and compatible
c1017a4c 4 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4
LT
5 */
6
1da177e4 7#include <linux/init.h>
67be4458 8#include <linux/err.h>
5e24c1c1 9#include <linux/isa.h>
1da177e4 10#include <linux/ioport.h>
65a77217 11#include <linux/module.h>
1da177e4
LT
12#include <sound/core.h>
13#include <sound/sb.h>
14#include <sound/opl3.h>
1da177e4
LT
15#include <sound/initval.h>
16
c1017a4c 17MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1da177e4
LT
18MODULE_DESCRIPTION("Sound Blaster 1.0/2.0/Pro");
19MODULE_LICENSE("GPL");
1da177e4
LT
20
21static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
22static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
a67ff6a5 23static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
1da177e4
LT
24static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260 */
25static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
26static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 1,3 */
27
28module_param_array(index, int, NULL, 0444);
29MODULE_PARM_DESC(index, "Index value for Sound Blaster soundcard.");
30module_param_array(id, charp, NULL, 0444);
31MODULE_PARM_DESC(id, "ID string for Sound Blaster soundcard.");
32module_param_array(enable, bool, NULL, 0444);
33MODULE_PARM_DESC(enable, "Enable Sound Blaster soundcard.");
e992ef57 34module_param_hw_array(port, long, ioport, NULL, 0444);
1da177e4 35MODULE_PARM_DESC(port, "Port # for SB8 driver.");
e992ef57 36module_param_hw_array(irq, int, irq, NULL, 0444);
1da177e4 37MODULE_PARM_DESC(irq, "IRQ # for SB8 driver.");
e992ef57 38module_param_hw_array(dma8, int, dma, NULL, 0444);
1da177e4
LT
39MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
40
41struct snd_sb8 {
42 struct resource *fm_res; /* used to block FM i/o region for legacy cards */
67be4458 43 struct snd_sb *chip;
1da177e4
LT
44};
45
7d12e780 46static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
1da177e4 47{
029d64b0 48 struct snd_sb *chip = dev_id;
1da177e4
LT
49
50 if (chip->open & SB_OPEN_PCM) {
51 return snd_sb8dsp_interrupt(chip);
52 } else {
53 return snd_sb8dsp_midi_interrupt(chip);
54 }
55}
56
1bff292e 57static int snd_sb8_match(struct device *pdev, unsigned int dev)
5e24c1c1
TI
58{
59 if (!enable[dev])
60 return 0;
61 if (irq[dev] == SNDRV_AUTO_IRQ) {
0418ff0c 62 dev_err(pdev, "please specify irq\n");
5e24c1c1
TI
63 return 0;
64 }
65 if (dma8[dev] == SNDRV_AUTO_DMA) {
0418ff0c 66 dev_err(pdev, "please specify dma8\n");
5e24c1c1
TI
67 return 0;
68 }
69 return 1;
70}
71
1bff292e 72static int snd_sb8_probe(struct device *pdev, unsigned int dev)
1da177e4 73{
029d64b0
TI
74 struct snd_sb *chip;
75 struct snd_card *card;
1da177e4 76 struct snd_sb8 *acard;
029d64b0 77 struct snd_opl3 *opl3;
1da177e4
LT
78 int err;
79
5eab6cb0
TI
80 err = snd_devm_card_new(pdev, index[dev], id[dev], THIS_MODULE,
81 sizeof(struct snd_sb8), &card);
c95eadd2
TI
82 if (err < 0)
83 return err;
67be4458 84 acard = card->private_data;
1da177e4 85
a28591f6
AG
86 /*
87 * Block the 0x388 port to avoid PnP conflicts.
88 * No need to check this value after request_region,
89 * as we never do anything with it.
90 */
5eab6cb0
TI
91 acard->fm_res = devm_request_region(card->dev, 0x388, 4,
92 "SoundBlaster FM");
1da177e4 93
67be4458 94 if (port[dev] != SNDRV_AUTO_PORT) {
10dc8ad5
TI
95 err = snd_sbdsp_create(card, port[dev], irq[dev],
96 snd_sb8_interrupt, dma8[dev],
97 -1, SB_HW_AUTO, &chip);
98 if (err < 0)
5eab6cb0 99 return err;
67be4458
TI
100 } else {
101 /* auto-probe legacy ports */
2a076d0a 102 static const unsigned long possible_ports[] = {
67be4458
TI
103 0x220, 0x240, 0x260,
104 };
105 int i;
106 for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
107 err = snd_sbdsp_create(card, possible_ports[i],
108 irq[dev],
109 snd_sb8_interrupt,
110 dma8[dev],
111 -1,
112 SB_HW_AUTO,
113 &chip);
114 if (err >= 0) {
115 port[dev] = possible_ports[i];
116 break;
117 }
118 }
5eab6cb0
TI
119 if (i >= ARRAY_SIZE(possible_ports))
120 return -EINVAL;
67be4458
TI
121 }
122 acard->chip = chip;
123
1da177e4 124 if (chip->hardware >= SB_HW_16) {
1da177e4 125 if (chip->hardware == SB_HW_ALS100)
43bcd973 126 snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
1da177e4
LT
127 port[dev]);
128 else
43bcd973
TI
129 snd_printk(KERN_WARNING "SB 16 chip detected at 0x%lx, try snd-sb16 module\n",
130 port[dev]);
5eab6cb0 131 return -ENODEV;
1da177e4
LT
132 }
133
10dc8ad5
TI
134 err = snd_sb8dsp_pcm(chip, 0);
135 if (err < 0)
5eab6cb0 136 return err;
43bcd973 137
10dc8ad5
TI
138 err = snd_sbmixer_new(chip);
139 if (err < 0)
5eab6cb0 140 return err;
43bcd973 141
1da177e4 142 if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) {
10dc8ad5
TI
143 err = snd_opl3_create(card, chip->port + 8, 0,
144 OPL3_HW_AUTO, 1, &opl3);
145 if (err < 0)
43bcd973 146 snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8);
1da177e4 147 } else {
10dc8ad5
TI
148 err = snd_opl3_create(card, chip->port, chip->port + 2,
149 OPL3_HW_AUTO, 1, &opl3);
150 if (err < 0) {
43bcd973 151 snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n",
1da177e4
LT
152 chip->port, chip->port + 2);
153 }
154 }
155 if (err >= 0) {
10dc8ad5
TI
156 err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
157 if (err < 0)
5eab6cb0 158 return err;
1da177e4
LT
159 }
160
10dc8ad5
TI
161 err = snd_sb8dsp_midi(chip, 0);
162 if (err < 0)
5eab6cb0 163 return err;
1da177e4
LT
164
165 strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8");
166 strcpy(card->shortname, chip->name);
167 sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d",
168 chip->name,
169 chip->port,
170 irq[dev], dma8[dev]);
43bcd973 171
10dc8ad5
TI
172 err = snd_card_register(card);
173 if (err < 0)
5eab6cb0 174 return err;
43bcd973 175
5e24c1c1 176 dev_set_drvdata(pdev, card);
1da177e4 177 return 0;
67be4458
TI
178}
179
180#ifdef CONFIG_PM
5e24c1c1
TI
181static int snd_sb8_suspend(struct device *dev, unsigned int n,
182 pm_message_t state)
67be4458 183{
5e24c1c1 184 struct snd_card *card = dev_get_drvdata(dev);
67be4458
TI
185 struct snd_sb8 *acard = card->private_data;
186 struct snd_sb *chip = acard->chip;
187
188 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
67be4458
TI
189 snd_sbmixer_suspend(chip);
190 return 0;
191}
192
5e24c1c1 193static int snd_sb8_resume(struct device *dev, unsigned int n)
1da177e4 194{
5e24c1c1 195 struct snd_card *card = dev_get_drvdata(dev);
67be4458
TI
196 struct snd_sb8 *acard = card->private_data;
197 struct snd_sb *chip = acard->chip;
198
199 snd_sbdsp_reset(chip);
200 snd_sbmixer_resume(chip);
201 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
202 return 0;
1da177e4 203}
67be4458
TI
204#endif
205
83c51c0a 206#define DEV_NAME "sb8"
67be4458 207
5e24c1c1
TI
208static struct isa_driver snd_sb8_driver = {
209 .match = snd_sb8_match,
67be4458 210 .probe = snd_sb8_probe,
67be4458
TI
211#ifdef CONFIG_PM
212 .suspend = snd_sb8_suspend,
213 .resume = snd_sb8_resume,
214#endif
215 .driver = {
83c51c0a 216 .name = DEV_NAME
67be4458
TI
217 },
218};
1da177e4 219
bb974b8f 220module_isa_driver(snd_sb8_driver, SNDRV_CARDS);