aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/isa/sb/sb8.c154
1 files changed, 107 insertions, 47 deletions
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 5116038fcb4a..0a3d55d639a9 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -21,13 +21,14 @@
21 21
22#include <sound/driver.h> 22#include <sound/driver.h>
23#include <linux/init.h> 23#include <linux/init.h>
24#include <linux/err.h>
25#include <linux/platform_device.h>
24#include <linux/slab.h> 26#include <linux/slab.h>
25#include <linux/ioport.h> 27#include <linux/ioport.h>
26#include <linux/moduleparam.h> 28#include <linux/moduleparam.h>
27#include <sound/core.h> 29#include <sound/core.h>
28#include <sound/sb.h> 30#include <sound/sb.h>
29#include <sound/opl3.h> 31#include <sound/opl3.h>
30#define SNDRV_LEGACY_AUTO_PROBE
31#include <sound/initval.h> 32#include <sound/initval.h>
32 33
33MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 34MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
@@ -57,10 +58,9 @@ MODULE_PARM_DESC(dma8, "8-bit DMA # for SB8 driver.");
57 58
58struct snd_sb8 { 59struct snd_sb8 {
59 struct resource *fm_res; /* used to block FM i/o region for legacy cards */ 60 struct resource *fm_res; /* used to block FM i/o region for legacy cards */
61 struct snd_sb *chip;
60}; 62};
61 63
62static struct snd_card *snd_sb8_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
63
64static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs) 64static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs)
65{ 65{
66 struct snd_sb *chip = dev_id; 66 struct snd_sb *chip = dev_id;
@@ -81,8 +81,9 @@ static void snd_sb8_free(struct snd_card *card)
81 release_and_free_resource(acard->fm_res); 81 release_and_free_resource(acard->fm_res);
82} 82}
83 83
84static int __init snd_sb8_probe(int dev) 84static int __init snd_sb8_probe(struct platform_device *pdev)
85{ 85{
86 int dev = pdev->id;
86 struct snd_sb *chip; 87 struct snd_sb *chip;
87 struct snd_card *card; 88 struct snd_card *card;
88 struct snd_sb8 *acard; 89 struct snd_sb8 *acard;
@@ -93,20 +94,44 @@ static int __init snd_sb8_probe(int dev)
93 sizeof(struct snd_sb8)); 94 sizeof(struct snd_sb8));
94 if (card == NULL) 95 if (card == NULL)
95 return -ENOMEM; 96 return -ENOMEM;
96 acard = (struct snd_sb8 *)card->private_data; 97 acard = card->private_data;
97 card->private_free = snd_sb8_free; 98 card->private_free = snd_sb8_free;
98 99
99 /* block the 0x388 port to avoid PnP conflicts */ 100 /* block the 0x388 port to avoid PnP conflicts */
100 acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); 101 acard->fm_res = request_region(0x388, 4, "SoundBlaster FM");
101 102
102 if ((err = snd_sbdsp_create(card, port[dev], irq[dev], 103 if (port[dev] != SNDRV_AUTO_PORT) {
103 snd_sb8_interrupt, 104 if ((err = snd_sbdsp_create(card, port[dev], irq[dev],
104 dma8[dev], 105 snd_sb8_interrupt,
105 -1, 106 dma8[dev],
106 SB_HW_AUTO, 107 -1,
107 &chip)) < 0) 108 SB_HW_AUTO,
108 goto _err; 109 &chip)) < 0)
109 110 goto _err;
111 } else {
112 /* auto-probe legacy ports */
113 static unsigned long possible_ports[] = {
114 0x220, 0x240, 0x260,
115 };
116 int i;
117 for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
118 err = snd_sbdsp_create(card, possible_ports[i],
119 irq[dev],
120 snd_sb8_interrupt,
121 dma8[dev],
122 -1,
123 SB_HW_AUTO,
124 &chip);
125 if (err >= 0) {
126 port[dev] = possible_ports[i];
127 break;
128 }
129 }
130 if (i >= ARRAY_SIZE(possible_ports))
131 goto _err;
132 }
133 acard->chip = chip;
134
110 if (chip->hardware >= SB_HW_16) { 135 if (chip->hardware >= SB_HW_16) {
111 if (chip->hardware == SB_HW_ALS100) 136 if (chip->hardware == SB_HW_ALS100)
112 snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n", 137 snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n",
@@ -153,13 +178,12 @@ static int __init snd_sb8_probe(int dev)
153 chip->port, 178 chip->port,
154 irq[dev], dma8[dev]); 179 irq[dev], dma8[dev]);
155 180
156 if ((err = snd_card_set_generic_dev(card)) < 0) 181 snd_card_set_dev(card, &pdev->dev);
157 goto _err;
158 182
159 if ((err = snd_card_register(card)) < 0) 183 if ((err = snd_card_register(card)) < 0)
160 goto _err; 184 goto _err;
161 185
162 snd_sb8_cards[dev] = card; 186 platform_set_drvdata(pdev, card);
163 return 0; 187 return 0;
164 188
165 _err: 189 _err:
@@ -167,53 +191,89 @@ static int __init snd_sb8_probe(int dev)
167 return err; 191 return err;
168} 192}
169 193
170static int __init snd_card_sb8_legacy_auto_probe(unsigned long xport) 194static int snd_sb8_remove(struct platform_device *pdev)
195{
196 snd_card_free(platform_get_drvdata(pdev));
197 platform_set_drvdata(pdev, NULL);
198 return 0;
199}
200
201#ifdef CONFIG_PM
202static int snd_sb8_suspend(struct platform_device *dev, pm_message_t state)
203{
204 struct snd_card *card = platform_get_drvdata(dev);
205 struct snd_sb8 *acard = card->private_data;
206 struct snd_sb *chip = acard->chip;
207
208 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
209 snd_pcm_suspend_all(chip->pcm);
210 snd_sbmixer_suspend(chip);
211 return 0;
212}
213
214static int snd_sb8_resume(struct platform_device *dev)
171{ 215{
172 static int dev; 216 struct snd_card *card = platform_get_drvdata(dev);
173 int res; 217 struct snd_sb8 *acard = card->private_data;
174 218 struct snd_sb *chip = acard->chip;
175 for ( ; dev < SNDRV_CARDS; dev++) { 219
176 if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT) 220 snd_sbdsp_reset(chip);
177 continue; 221 snd_sbmixer_resume(chip);
178 port[dev] = xport; 222 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
179 res = snd_sb8_probe(dev); 223 return 0;
180 if (res < 0)
181 port[dev] = SNDRV_AUTO_PORT;
182 return res;
183 }
184 return -ENODEV;
185} 224}
225#endif
226
227#define SND_SB8_DRIVER "snd_sb8"
228
229static struct platform_driver snd_sb8_driver = {
230 .probe = snd_sb8_probe,
231 .remove = snd_sb8_remove,
232#ifdef CONFIG_PM
233 .suspend = snd_sb8_suspend,
234 .resume = snd_sb8_resume,
235#endif
236 .driver = {
237 .name = SND_SB8_DRIVER
238 },
239};
186 240
187static int __init alsa_card_sb8_init(void) 241static int __init alsa_card_sb8_init(void)
188{ 242{
189 static unsigned long possible_ports[] = {0x220, 0x240, 0x260, -1}; 243 int i, cards, err;
190 int dev, cards, i; 244
191 245 err = platform_driver_register(&snd_sb8_driver);
192 for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) { 246 if (err < 0)
193 if (port[dev] == SNDRV_AUTO_PORT) 247 return err;
194 continue; 248
195 if (snd_sb8_probe(dev) >= 0) 249 cards = 0;
196 cards++; 250 for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
251 struct platform_device *device;
252 device = platform_device_register_simple(SND_SB8_DRIVER,
253 i, NULL, 0);
254 if (IS_ERR(device)) {
255 err = PTR_ERR(device);
256 goto errout;
257 }
258 cards++;
197 } 259 }
198 i = snd_legacy_auto_probe(possible_ports, snd_card_sb8_legacy_auto_probe);
199 if (i > 0)
200 cards += i;
201
202 if (!cards) { 260 if (!cards) {
203#ifdef MODULE 261#ifdef MODULE
204 snd_printk(KERN_ERR "Sound Blaster soundcard not found or device busy\n"); 262 snd_printk(KERN_ERR "Sound Blaster soundcard not found or device busy\n");
205#endif 263#endif
206 return -ENODEV; 264 err = -ENODEV;
265 goto errout;
207 } 266 }
208 return 0; 267 return 0;
268
269 errout:
270 platform_driver_unregister(&snd_sb8_driver);
271 return err;
209} 272}
210 273
211static void __exit alsa_card_sb8_exit(void) 274static void __exit alsa_card_sb8_exit(void)
212{ 275{
213 int idx; 276 platform_driver_unregister(&snd_sb8_driver);
214
215 for (idx = 0; idx < SNDRV_CARDS; idx++)
216 snd_card_free(snd_sb8_cards[idx]);
217} 277}
218 278
219module_init(alsa_card_sb8_init) 279module_init(alsa_card_sb8_init)