diff options
Diffstat (limited to 'sound/isa/opl3sa2.c')
-rw-r--r-- | sound/isa/opl3sa2.c | 556 |
1 files changed, 308 insertions, 248 deletions
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 47cabda792b6..ca359e0c674b 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c | |||
@@ -21,6 +21,8 @@ | |||
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/interrupt.h> | 26 | #include <linux/interrupt.h> |
25 | #include <linux/pm.h> | 27 | #include <linux/pm.h> |
26 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
@@ -88,6 +90,10 @@ MODULE_PARM_DESC(dma2, "DMA2 # for OPL3-SA driver."); | |||
88 | module_param_array(opl3sa3_ymode, int, NULL, 0444); | 90 | module_param_array(opl3sa3_ymode, int, NULL, 0444); |
89 | MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: Desktop/Large Notebook/Small Notebook/HiFi."); | 91 | MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: Desktop/Large Notebook/Small Notebook/HiFi."); |
90 | 92 | ||
93 | static struct platform_device *platform_devices[SNDRV_CARDS]; | ||
94 | static int pnp_registered; | ||
95 | static int pnpc_registered; | ||
96 | |||
91 | /* control ports */ | 97 | /* control ports */ |
92 | #define OPL3SA2_PM_CTRL 0x01 | 98 | #define OPL3SA2_PM_CTRL 0x01 |
93 | #define OPL3SA2_SYS_CTRL 0x02 | 99 | #define OPL3SA2_SYS_CTRL 0x02 |
@@ -115,34 +121,23 @@ MODULE_PARM_DESC(opl3sa3_ymode, "Speaker size selection for 3D Enhancement mode: | |||
115 | #define OPL3SA2_PM_D0 0x00 | 121 | #define OPL3SA2_PM_D0 0x00 |
116 | #define OPL3SA2_PM_D3 (OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX) | 122 | #define OPL3SA2_PM_D3 (OPL3SA2_PM_ADOWN|OPL3SA2_PM_PSV|OPL3SA2_PM_PDN|OPL3SA2_PM_PDX) |
117 | 123 | ||
118 | typedef struct snd_opl3sa2 opl3sa2_t; | ||
119 | |||
120 | struct snd_opl3sa2 { | 124 | struct snd_opl3sa2 { |
121 | snd_card_t *card; | 125 | struct snd_card *card; |
122 | int version; /* 2 or 3 */ | 126 | int version; /* 2 or 3 */ |
123 | unsigned long port; /* control port */ | 127 | unsigned long port; /* control port */ |
124 | struct resource *res_port; /* control port resource */ | 128 | struct resource *res_port; /* control port resource */ |
125 | int irq; | 129 | int irq; |
126 | int single_dma; | 130 | int single_dma; |
127 | spinlock_t reg_lock; | 131 | spinlock_t reg_lock; |
128 | snd_hwdep_t *synth; | 132 | struct snd_hwdep *synth; |
129 | snd_rawmidi_t *rmidi; | 133 | struct snd_rawmidi *rmidi; |
130 | cs4231_t *cs4231; | 134 | struct snd_cs4231 *cs4231; |
131 | #ifdef CONFIG_PNP | ||
132 | struct pnp_dev *dev; | ||
133 | #endif | ||
134 | unsigned char ctlregs[0x20]; | 135 | unsigned char ctlregs[0x20]; |
135 | int ymode; /* SL added */ | 136 | int ymode; /* SL added */ |
136 | snd_kcontrol_t *master_switch; | 137 | struct snd_kcontrol *master_switch; |
137 | snd_kcontrol_t *master_volume; | 138 | struct snd_kcontrol *master_volume; |
138 | #ifdef CONFIG_PM | ||
139 | void (*cs4231_suspend)(cs4231_t *); | ||
140 | void (*cs4231_resume)(cs4231_t *); | ||
141 | #endif | ||
142 | }; | 139 | }; |
143 | 140 | ||
144 | static snd_card_t *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
145 | |||
146 | #define PFX "opl3sa2: " | 141 | #define PFX "opl3sa2: " |
147 | 142 | ||
148 | #ifdef CONFIG_PNP | 143 | #ifdef CONFIG_PNP |
@@ -176,7 +171,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_opl3sa2_pnpids); | |||
176 | 171 | ||
177 | 172 | ||
178 | /* read control port (w/o spinlock) */ | 173 | /* read control port (w/o spinlock) */ |
179 | static unsigned char __snd_opl3sa2_read(opl3sa2_t *chip, unsigned char reg) | 174 | static unsigned char __snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char reg) |
180 | { | 175 | { |
181 | unsigned char result; | 176 | unsigned char result; |
182 | #if 0 | 177 | #if 0 |
@@ -192,7 +187,7 @@ static unsigned char __snd_opl3sa2_read(opl3sa2_t *chip, unsigned char reg) | |||
192 | } | 187 | } |
193 | 188 | ||
194 | /* read control port (with spinlock) */ | 189 | /* read control port (with spinlock) */ |
195 | static unsigned char snd_opl3sa2_read(opl3sa2_t *chip, unsigned char reg) | 190 | static unsigned char snd_opl3sa2_read(struct snd_opl3sa2 *chip, unsigned char reg) |
196 | { | 191 | { |
197 | unsigned long flags; | 192 | unsigned long flags; |
198 | unsigned char result; | 193 | unsigned char result; |
@@ -204,7 +199,7 @@ static unsigned char snd_opl3sa2_read(opl3sa2_t *chip, unsigned char reg) | |||
204 | } | 199 | } |
205 | 200 | ||
206 | /* write control port (w/o spinlock) */ | 201 | /* write control port (w/o spinlock) */ |
207 | static void __snd_opl3sa2_write(opl3sa2_t *chip, unsigned char reg, unsigned char value) | 202 | static void __snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsigned char value) |
208 | { | 203 | { |
209 | #if 0 | 204 | #if 0 |
210 | outb(0x1d, port); /* password */ | 205 | outb(0x1d, port); /* password */ |
@@ -215,7 +210,7 @@ static void __snd_opl3sa2_write(opl3sa2_t *chip, unsigned char reg, unsigned cha | |||
215 | } | 210 | } |
216 | 211 | ||
217 | /* write control port (with spinlock) */ | 212 | /* write control port (with spinlock) */ |
218 | static void snd_opl3sa2_write(opl3sa2_t *chip, unsigned char reg, unsigned char value) | 213 | static void snd_opl3sa2_write(struct snd_opl3sa2 *chip, unsigned char reg, unsigned char value) |
219 | { | 214 | { |
220 | unsigned long flags; | 215 | unsigned long flags; |
221 | spin_lock_irqsave(&chip->reg_lock, flags); | 216 | spin_lock_irqsave(&chip->reg_lock, flags); |
@@ -223,9 +218,9 @@ static void snd_opl3sa2_write(opl3sa2_t *chip, unsigned char reg, unsigned char | |||
223 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 218 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
224 | } | 219 | } |
225 | 220 | ||
226 | static int __init snd_opl3sa2_detect(opl3sa2_t *chip) | 221 | static int __init snd_opl3sa2_detect(struct snd_opl3sa2 *chip) |
227 | { | 222 | { |
228 | snd_card_t *card; | 223 | struct snd_card *card; |
229 | unsigned long port; | 224 | unsigned long port; |
230 | unsigned char tmp, tmp1; | 225 | unsigned char tmp, tmp1; |
231 | char str[2]; | 226 | char str[2]; |
@@ -298,7 +293,7 @@ static int __init snd_opl3sa2_detect(opl3sa2_t *chip) | |||
298 | static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 293 | static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
299 | { | 294 | { |
300 | unsigned short status; | 295 | unsigned short status; |
301 | opl3sa2_t *chip = dev_id; | 296 | struct snd_opl3sa2 *chip = dev_id; |
302 | int handled = 0; | 297 | int handled = 0; |
303 | 298 | ||
304 | if (chip == NULL || chip->card == NULL) | 299 | if (chip == NULL || chip->card == NULL) |
@@ -340,7 +335,7 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs * | |||
340 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ | 335 | .get = snd_opl3sa2_get_single, .put = snd_opl3sa2_put_single, \ |
341 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } | 336 | .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } |
342 | 337 | ||
343 | static int snd_opl3sa2_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | 338 | static int snd_opl3sa2_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
344 | { | 339 | { |
345 | int mask = (kcontrol->private_value >> 16) & 0xff; | 340 | int mask = (kcontrol->private_value >> 16) & 0xff; |
346 | 341 | ||
@@ -351,9 +346,9 @@ static int snd_opl3sa2_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t | |||
351 | return 0; | 346 | return 0; |
352 | } | 347 | } |
353 | 348 | ||
354 | static int snd_opl3sa2_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 349 | static int snd_opl3sa2_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
355 | { | 350 | { |
356 | opl3sa2_t *chip = snd_kcontrol_chip(kcontrol); | 351 | struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); |
357 | unsigned long flags; | 352 | unsigned long flags; |
358 | int reg = kcontrol->private_value & 0xff; | 353 | int reg = kcontrol->private_value & 0xff; |
359 | int shift = (kcontrol->private_value >> 8) & 0xff; | 354 | int shift = (kcontrol->private_value >> 8) & 0xff; |
@@ -368,9 +363,9 @@ static int snd_opl3sa2_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ | |||
368 | return 0; | 363 | return 0; |
369 | } | 364 | } |
370 | 365 | ||
371 | static int snd_opl3sa2_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 366 | static int snd_opl3sa2_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
372 | { | 367 | { |
373 | opl3sa2_t *chip = snd_kcontrol_chip(kcontrol); | 368 | struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); |
374 | unsigned long flags; | 369 | unsigned long flags; |
375 | int reg = kcontrol->private_value & 0xff; | 370 | int reg = kcontrol->private_value & 0xff; |
376 | int shift = (kcontrol->private_value >> 8) & 0xff; | 371 | int shift = (kcontrol->private_value >> 8) & 0xff; |
@@ -398,7 +393,7 @@ static int snd_opl3sa2_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ | |||
398 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ | 393 | .get = snd_opl3sa2_get_double, .put = snd_opl3sa2_put_double, \ |
399 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } | 394 | .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } |
400 | 395 | ||
401 | static int snd_opl3sa2_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | 396 | static int snd_opl3sa2_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
402 | { | 397 | { |
403 | int mask = (kcontrol->private_value >> 24) & 0xff; | 398 | int mask = (kcontrol->private_value >> 24) & 0xff; |
404 | 399 | ||
@@ -409,9 +404,9 @@ static int snd_opl3sa2_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t | |||
409 | return 0; | 404 | return 0; |
410 | } | 405 | } |
411 | 406 | ||
412 | static int snd_opl3sa2_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 407 | static int snd_opl3sa2_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
413 | { | 408 | { |
414 | opl3sa2_t *chip = snd_kcontrol_chip(kcontrol); | 409 | struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); |
415 | unsigned long flags; | 410 | unsigned long flags; |
416 | int left_reg = kcontrol->private_value & 0xff; | 411 | int left_reg = kcontrol->private_value & 0xff; |
417 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | 412 | int right_reg = (kcontrol->private_value >> 8) & 0xff; |
@@ -431,9 +426,9 @@ static int snd_opl3sa2_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ | |||
431 | return 0; | 426 | return 0; |
432 | } | 427 | } |
433 | 428 | ||
434 | static int snd_opl3sa2_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 429 | static int snd_opl3sa2_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
435 | { | 430 | { |
436 | opl3sa2_t *chip = snd_kcontrol_chip(kcontrol); | 431 | struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); |
437 | unsigned long flags; | 432 | unsigned long flags; |
438 | int left_reg = kcontrol->private_value & 0xff; | 433 | int left_reg = kcontrol->private_value & 0xff; |
439 | int right_reg = (kcontrol->private_value >> 8) & 0xff; | 434 | int right_reg = (kcontrol->private_value >> 8) & 0xff; |
@@ -471,31 +466,31 @@ static int snd_opl3sa2_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ | |||
471 | return change; | 466 | return change; |
472 | } | 467 | } |
473 | 468 | ||
474 | static snd_kcontrol_new_t snd_opl3sa2_controls[] = { | 469 | static struct snd_kcontrol_new snd_opl3sa2_controls[] = { |
475 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), | 470 | OPL3SA2_DOUBLE("Master Playback Switch", 0, 0x07, 0x08, 7, 7, 1, 1), |
476 | OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1), | 471 | OPL3SA2_DOUBLE("Master Playback Volume", 0, 0x07, 0x08, 0, 0, 15, 1), |
477 | OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), | 472 | OPL3SA2_SINGLE("Mic Playback Switch", 0, 0x09, 7, 1, 1), |
478 | OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1) | 473 | OPL3SA2_SINGLE("Mic Playback Volume", 0, 0x09, 0, 31, 1) |
479 | }; | 474 | }; |
480 | 475 | ||
481 | static snd_kcontrol_new_t snd_opl3sa2_tone_controls[] = { | 476 | static struct snd_kcontrol_new snd_opl3sa2_tone_controls[] = { |
482 | OPL3SA2_DOUBLE("3D Control - Wide", 0, 0x14, 0x14, 4, 0, 7, 0), | 477 | OPL3SA2_DOUBLE("3D Control - Wide", 0, 0x14, 0x14, 4, 0, 7, 0), |
483 | OPL3SA2_DOUBLE("Tone Control - Bass", 0, 0x15, 0x15, 4, 0, 7, 0), | 478 | OPL3SA2_DOUBLE("Tone Control - Bass", 0, 0x15, 0x15, 4, 0, 7, 0), |
484 | OPL3SA2_DOUBLE("Tone Control - Treble", 0, 0x16, 0x16, 4, 0, 7, 0) | 479 | OPL3SA2_DOUBLE("Tone Control - Treble", 0, 0x16, 0x16, 4, 0, 7, 0) |
485 | }; | 480 | }; |
486 | 481 | ||
487 | static void snd_opl3sa2_master_free(snd_kcontrol_t *kcontrol) | 482 | static void snd_opl3sa2_master_free(struct snd_kcontrol *kcontrol) |
488 | { | 483 | { |
489 | opl3sa2_t *chip = snd_kcontrol_chip(kcontrol); | 484 | struct snd_opl3sa2 *chip = snd_kcontrol_chip(kcontrol); |
490 | chip->master_switch = NULL; | 485 | chip->master_switch = NULL; |
491 | chip->master_volume = NULL; | 486 | chip->master_volume = NULL; |
492 | } | 487 | } |
493 | 488 | ||
494 | static int __init snd_opl3sa2_mixer(opl3sa2_t *chip) | 489 | static int __init snd_opl3sa2_mixer(struct snd_opl3sa2 *chip) |
495 | { | 490 | { |
496 | snd_card_t *card = chip->card; | 491 | struct snd_card *card = chip->card; |
497 | snd_ctl_elem_id_t id1, id2; | 492 | struct snd_ctl_elem_id id1, id2; |
498 | snd_kcontrol_t *kctl; | 493 | struct snd_kcontrol *kctl; |
499 | unsigned int idx; | 494 | unsigned int idx; |
500 | int err; | 495 | int err; |
501 | 496 | ||
@@ -505,21 +500,29 @@ static int __init snd_opl3sa2_mixer(opl3sa2_t *chip) | |||
505 | /* reassign AUX0 to CD */ | 500 | /* reassign AUX0 to CD */ |
506 | strcpy(id1.name, "Aux Playback Switch"); | 501 | strcpy(id1.name, "Aux Playback Switch"); |
507 | strcpy(id2.name, "CD Playback Switch"); | 502 | strcpy(id2.name, "CD Playback Switch"); |
508 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | 503 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { |
504 | snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); | ||
509 | return err; | 505 | return err; |
506 | } | ||
510 | strcpy(id1.name, "Aux Playback Volume"); | 507 | strcpy(id1.name, "Aux Playback Volume"); |
511 | strcpy(id2.name, "CD Playback Volume"); | 508 | strcpy(id2.name, "CD Playback Volume"); |
512 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | 509 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { |
510 | snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); | ||
513 | return err; | 511 | return err; |
512 | } | ||
514 | /* reassign AUX1 to FM */ | 513 | /* reassign AUX1 to FM */ |
515 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; | 514 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; |
516 | strcpy(id2.name, "FM Playback Switch"); | 515 | strcpy(id2.name, "FM Playback Switch"); |
517 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | 516 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { |
517 | snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); | ||
518 | return err; | 518 | return err; |
519 | } | ||
519 | strcpy(id1.name, "Aux Playback Volume"); | 520 | strcpy(id1.name, "Aux Playback Volume"); |
520 | strcpy(id2.name, "FM Playback Volume"); | 521 | strcpy(id2.name, "FM Playback Volume"); |
521 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) | 522 | if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { |
523 | snd_printk(KERN_ERR "Cannot rename opl3sa2 control\n"); | ||
522 | return err; | 524 | return err; |
525 | } | ||
523 | /* add OPL3SA2 controls */ | 526 | /* add OPL3SA2 controls */ |
524 | for (idx = 0; idx < ARRAY_SIZE(snd_opl3sa2_controls); idx++) { | 527 | for (idx = 0; idx < ARRAY_SIZE(snd_opl3sa2_controls); idx++) { |
525 | if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_opl3sa2_controls[idx], chip))) < 0) | 528 | if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_opl3sa2_controls[idx], chip))) < 0) |
@@ -539,22 +542,21 @@ static int __init snd_opl3sa2_mixer(opl3sa2_t *chip) | |||
539 | 542 | ||
540 | /* Power Management support functions */ | 543 | /* Power Management support functions */ |
541 | #ifdef CONFIG_PM | 544 | #ifdef CONFIG_PM |
542 | static int snd_opl3sa2_suspend(snd_card_t *card, pm_message_t state) | 545 | static int snd_opl3sa2_suspend(struct snd_card *card, pm_message_t state) |
543 | { | 546 | { |
544 | opl3sa2_t *chip = card->pm_private_data; | 547 | struct snd_opl3sa2 *chip = card->private_data; |
545 | |||
546 | snd_pcm_suspend_all(chip->cs4231->pcm); /* stop before saving regs */ | ||
547 | chip->cs4231_suspend(chip->cs4231); | ||
548 | 548 | ||
549 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
550 | chip->cs4231->suspend(chip->cs4231); | ||
549 | /* power down */ | 551 | /* power down */ |
550 | snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); | 552 | snd_opl3sa2_write(chip, OPL3SA2_PM_CTRL, OPL3SA2_PM_D3); |
551 | 553 | ||
552 | return 0; | 554 | return 0; |
553 | } | 555 | } |
554 | 556 | ||
555 | static int snd_opl3sa2_resume(snd_card_t *card) | 557 | static int snd_opl3sa2_resume(struct snd_card *card) |
556 | { | 558 | { |
557 | opl3sa2_t *chip = card->pm_private_data; | 559 | struct snd_opl3sa2 *chip = card->private_data; |
558 | int i; | 560 | int i; |
559 | 561 | ||
560 | /* power up */ | 562 | /* power up */ |
@@ -570,26 +572,25 @@ static int snd_opl3sa2_resume(snd_card_t *card) | |||
570 | snd_opl3sa2_write(chip, i, chip->ctlregs[i]); | 572 | snd_opl3sa2_write(chip, i, chip->ctlregs[i]); |
571 | } | 573 | } |
572 | /* restore cs4231 */ | 574 | /* restore cs4231 */ |
573 | chip->cs4231_resume(chip->cs4231); | 575 | chip->cs4231->resume(chip->cs4231); |
574 | 576 | ||
577 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
575 | return 0; | 578 | return 0; |
576 | } | 579 | } |
577 | #endif /* CONFIG_PM */ | 580 | #endif /* CONFIG_PM */ |
578 | 581 | ||
579 | #ifdef CONFIG_PNP | 582 | #ifdef CONFIG_PNP |
580 | static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip, | 583 | static int __init snd_opl3sa2_pnp(int dev, struct snd_opl3sa2 *chip, |
581 | struct pnp_dev *pdev, | 584 | struct pnp_dev *pdev) |
582 | int isapnp) | ||
583 | { | 585 | { |
584 | struct pnp_resource_table * cfg; | 586 | struct pnp_resource_table * cfg; |
585 | int err; | 587 | int err; |
586 | 588 | ||
587 | if (!isapnp && pnp_device_is_isapnp(pdev)) | ||
588 | return -ENOENT; /* we have another procedure - card */ | ||
589 | |||
590 | cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | 589 | cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); |
591 | if (!cfg) | 590 | if (!cfg) { |
591 | snd_printk(KERN_ERR PFX "cannot allocate pnp cfg\n"); | ||
592 | return -ENOMEM; | 592 | return -ENOMEM; |
593 | } | ||
593 | /* PnP initialization */ | 594 | /* PnP initialization */ |
594 | pnp_init_resource_table(cfg); | 595 | pnp_init_resource_table(cfg); |
595 | if (sb_port[dev] != SNDRV_AUTO_PORT) | 596 | if (sb_port[dev] != SNDRV_AUTO_PORT) |
@@ -609,8 +610,8 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip, | |||
609 | if (irq[dev] != SNDRV_AUTO_IRQ) | 610 | if (irq[dev] != SNDRV_AUTO_IRQ) |
610 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); | 611 | pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); |
611 | err = pnp_manual_config_dev(pdev, cfg, 0); | 612 | err = pnp_manual_config_dev(pdev, cfg, 0); |
612 | if (err < 0 && isapnp) | 613 | if (err < 0) |
613 | snd_printk(KERN_ERR "PnP manual resources are invalid, using auto config\n"); | 614 | snd_printk(KERN_WARNING "PnP manual resources are invalid, using auto config\n"); |
614 | err = pnp_activate_dev(pdev); | 615 | err = pnp_activate_dev(pdev); |
615 | if (err < 0) { | 616 | if (err < 0) { |
616 | kfree(cfg); | 617 | kfree(cfg); |
@@ -630,111 +631,47 @@ static int __init snd_opl3sa2_pnp(int dev, opl3sa2_t *chip, | |||
630 | snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n", | 631 | snd_printdd("%sPnP OPL3-SA: control port=0x%lx, dma1=%i, dma2=%i, irq=%i\n", |
631 | pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]); | 632 | pnp_device_is_pnpbios(pdev) ? "BIOS" : "ISA", port[dev], dma1[dev], dma2[dev], irq[dev]); |
632 | kfree(cfg); | 633 | kfree(cfg); |
633 | chip->dev = pdev; | ||
634 | return 0; | 634 | return 0; |
635 | } | 635 | } |
636 | |||
637 | static int __init snd_opl3sa2_cpnp(int dev, opl3sa2_t *chip, | ||
638 | struct pnp_card_link *card, | ||
639 | const struct pnp_card_device_id *id) | ||
640 | { | ||
641 | struct pnp_dev *pdev; | ||
642 | struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); | ||
643 | |||
644 | if (!cfg) | ||
645 | return -ENOMEM; | ||
646 | pdev = pnp_request_card_device(card, id->devs[0].id, NULL); | ||
647 | if (pdev == NULL) { | ||
648 | kfree(cfg); | ||
649 | return -EBUSY; | ||
650 | } | ||
651 | return snd_opl3sa2_pnp(dev, chip, pdev, 1); | ||
652 | } | ||
653 | #endif /* CONFIG_PNP */ | 636 | #endif /* CONFIG_PNP */ |
654 | 637 | ||
655 | static int snd_opl3sa2_free(opl3sa2_t *chip) | 638 | static void snd_opl3sa2_free(struct snd_card *card) |
656 | { | 639 | { |
640 | struct snd_opl3sa2 *chip = card->private_data; | ||
657 | if (chip->irq >= 0) | 641 | if (chip->irq >= 0) |
658 | free_irq(chip->irq, (void *)chip); | 642 | free_irq(chip->irq, (void *)chip); |
659 | release_and_free_resource(chip->res_port); | 643 | release_and_free_resource(chip->res_port); |
660 | kfree(chip); | ||
661 | return 0; | ||
662 | } | 644 | } |
663 | 645 | ||
664 | static int snd_opl3sa2_dev_free(snd_device_t *device) | 646 | static struct snd_card *snd_opl3sa2_card_new(int dev) |
665 | { | ||
666 | opl3sa2_t *chip = device->device_data; | ||
667 | return snd_opl3sa2_free(chip); | ||
668 | } | ||
669 | |||
670 | #ifdef CONFIG_PNP | ||
671 | #define is_isapnp_selected(dev) isapnp[dev] | ||
672 | #else | ||
673 | #define is_isapnp_selected(dev) 0 | ||
674 | #endif | ||
675 | |||
676 | static int __devinit snd_opl3sa2_probe(int dev, | ||
677 | struct pnp_dev *pdev, | ||
678 | struct pnp_card_link *pcard, | ||
679 | const struct pnp_card_device_id *pid) | ||
680 | { | 647 | { |
681 | int xirq, xdma1, xdma2; | 648 | struct snd_card *card; |
682 | snd_card_t *card; | ||
683 | struct snd_opl3sa2 *chip; | 649 | struct snd_opl3sa2 *chip; |
684 | cs4231_t *cs4231; | ||
685 | opl3_t *opl3; | ||
686 | static snd_device_ops_t ops = { | ||
687 | .dev_free = snd_opl3sa2_dev_free, | ||
688 | }; | ||
689 | int err; | ||
690 | |||
691 | if (! is_isapnp_selected(dev)) { | ||
692 | if (port[dev] == SNDRV_AUTO_PORT) { | ||
693 | snd_printk(KERN_ERR PFX "specify port\n"); | ||
694 | return -EINVAL; | ||
695 | } | ||
696 | if (wss_port[dev] == SNDRV_AUTO_PORT) { | ||
697 | snd_printk(KERN_ERR PFX "specify wss_port\n"); | ||
698 | return -EINVAL; | ||
699 | } | ||
700 | if (fm_port[dev] == SNDRV_AUTO_PORT) { | ||
701 | snd_printk(KERN_ERR PFX "specify fm_port\n"); | ||
702 | return -EINVAL; | ||
703 | } | ||
704 | if (midi_port[dev] == SNDRV_AUTO_PORT) { | ||
705 | snd_printk(KERN_ERR PFX "specify midi_port\n"); | ||
706 | return -EINVAL; | ||
707 | } | ||
708 | } | ||
709 | 650 | ||
710 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | 651 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_opl3sa2)); |
711 | if (card == NULL) | 652 | if (card == NULL) |
712 | return -ENOMEM; | 653 | return NULL; |
713 | strcpy(card->driver, "OPL3SA2"); | 654 | strcpy(card->driver, "OPL3SA2"); |
714 | strcpy(card->shortname, "Yamaha OPL3-SA2"); | 655 | strcpy(card->shortname, "Yamaha OPL3-SA2"); |
715 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 656 | chip = card->private_data; |
716 | if (chip == NULL) { | ||
717 | err = -ENOMEM; | ||
718 | goto __error; | ||
719 | } | ||
720 | spin_lock_init(&chip->reg_lock); | 657 | spin_lock_init(&chip->reg_lock); |
721 | chip->irq = -1; | 658 | chip->irq = -1; |
722 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) | ||
723 | goto __error; | ||
724 | #ifdef CONFIG_PNP | ||
725 | if (pdev) { | ||
726 | if ((err = snd_opl3sa2_pnp(dev, chip, pdev, 0)) < 0) | ||
727 | goto __error; | ||
728 | snd_card_set_dev(card, &pdev->dev); | ||
729 | } | ||
730 | if (pcard) { | ||
731 | if ((err = snd_opl3sa2_cpnp(dev, chip, pcard, pid)) < 0) | ||
732 | goto __error; | ||
733 | snd_card_set_dev(card, &pcard->card->dev); | ||
734 | } | ||
735 | #endif | ||
736 | chip->ymode = opl3sa3_ymode[dev] & 0x03 ; /* initialise this card from supplied (or default) parameter*/ | ||
737 | chip->card = card; | 659 | chip->card = card; |
660 | card->private_free = snd_opl3sa2_free; | ||
661 | return card; | ||
662 | } | ||
663 | |||
664 | static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev) | ||
665 | { | ||
666 | int xirq, xdma1, xdma2; | ||
667 | struct snd_opl3sa2 *chip; | ||
668 | struct snd_cs4231 *cs4231; | ||
669 | struct snd_opl3 *opl3; | ||
670 | int err; | ||
671 | |||
672 | /* initialise this card from supplied (or default) parameter*/ | ||
673 | chip = card->private_data; | ||
674 | chip->ymode = opl3sa3_ymode[dev] & 0x03 ; | ||
738 | chip->port = port[dev]; | 675 | chip->port = port[dev]; |
739 | xirq = irq[dev]; | 676 | xirq = irq[dev]; |
740 | xdma1 = dma1[dev]; | 677 | xdma1 = dma1[dev]; |
@@ -742,11 +679,10 @@ static int __devinit snd_opl3sa2_probe(int dev, | |||
742 | if (xdma2 < 0) | 679 | if (xdma2 < 0) |
743 | chip->single_dma = 1; | 680 | chip->single_dma = 1; |
744 | if ((err = snd_opl3sa2_detect(chip)) < 0) | 681 | if ((err = snd_opl3sa2_detect(chip)) < 0) |
745 | goto __error; | 682 | return err; |
746 | if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", (void *)chip)) { | 683 | if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", chip)) { |
747 | snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); | 684 | snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); |
748 | err = -ENODEV; | 685 | return -ENODEV; |
749 | goto __error; | ||
750 | } | 686 | } |
751 | chip->irq = xirq; | 687 | chip->irq = xirq; |
752 | if ((err = snd_cs4231_create(card, | 688 | if ((err = snd_cs4231_create(card, |
@@ -756,179 +692,303 @@ static int __devinit snd_opl3sa2_probe(int dev, | |||
756 | CS4231_HWSHARE_IRQ, | 692 | CS4231_HWSHARE_IRQ, |
757 | &cs4231)) < 0) { | 693 | &cs4231)) < 0) { |
758 | snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4); | 694 | snd_printd("Oops, WSS not detected at 0x%lx\n", wss_port[dev] + 4); |
759 | goto __error; | 695 | return err; |
760 | } | 696 | } |
761 | chip->cs4231 = cs4231; | 697 | chip->cs4231 = cs4231; |
762 | if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) | 698 | if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) |
763 | goto __error; | 699 | return err; |
764 | if ((err = snd_cs4231_mixer(cs4231)) < 0) | 700 | if ((err = snd_cs4231_mixer(cs4231)) < 0) |
765 | goto __error; | 701 | return err; |
766 | if ((err = snd_opl3sa2_mixer(chip)) < 0) | 702 | if ((err = snd_opl3sa2_mixer(chip)) < 0) |
767 | goto __error; | 703 | return err; |
768 | if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0) | 704 | if ((err = snd_cs4231_timer(cs4231, 0, NULL)) < 0) |
769 | goto __error; | 705 | return err; |
770 | if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { | 706 | if (fm_port[dev] >= 0x340 && fm_port[dev] < 0x400) { |
771 | if ((err = snd_opl3_create(card, fm_port[dev], | 707 | if ((err = snd_opl3_create(card, fm_port[dev], |
772 | fm_port[dev] + 2, | 708 | fm_port[dev] + 2, |
773 | OPL3_HW_OPL3, 0, &opl3)) < 0) | 709 | OPL3_HW_OPL3, 0, &opl3)) < 0) |
774 | goto __error; | 710 | return err; |
775 | if ((err = snd_opl3_timer_new(opl3, 1, 2)) < 0) | 711 | if ((err = snd_opl3_timer_new(opl3, 1, 2)) < 0) |
776 | goto __error; | 712 | return err; |
777 | if ((err = snd_opl3_hwdep_new(opl3, 0, 1, &chip->synth)) < 0) | 713 | if ((err = snd_opl3_hwdep_new(opl3, 0, 1, &chip->synth)) < 0) |
778 | goto __error; | 714 | return err; |
779 | } | 715 | } |
780 | if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { | 716 | if (midi_port[dev] >= 0x300 && midi_port[dev] < 0x340) { |
781 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, | 717 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_OPL3SA2, |
782 | midi_port[dev], 0, | 718 | midi_port[dev], 0, |
783 | xirq, 0, &chip->rmidi)) < 0) | 719 | xirq, 0, &chip->rmidi)) < 0) |
784 | goto __error; | 720 | return err; |
785 | } | 721 | } |
786 | #ifdef CONFIG_PM | ||
787 | chip->cs4231_suspend = chip->cs4231->suspend; | ||
788 | chip->cs4231_resume = chip->cs4231->resume; | ||
789 | /* now clear callbacks for cs4231 */ | ||
790 | chip->cs4231->suspend = NULL; | ||
791 | chip->cs4231->resume = NULL; | ||
792 | snd_card_set_isa_pm_callback(card, snd_opl3sa2_suspend, snd_opl3sa2_resume, chip); | ||
793 | #endif | ||
794 | |||
795 | sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", | 722 | sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", |
796 | card->shortname, chip->port, xirq, xdma1); | 723 | card->shortname, chip->port, xirq, xdma1); |
797 | if (dma2 >= 0) | 724 | if (dma2 >= 0) |
798 | sprintf(card->longname + strlen(card->longname), "&%d", xdma2); | 725 | sprintf(card->longname + strlen(card->longname), "&%d", xdma2); |
799 | 726 | ||
800 | if ((err = snd_card_set_generic_dev(card)) < 0) | 727 | return snd_card_register(card); |
801 | goto __error; | ||
802 | |||
803 | if ((err = snd_card_register(card)) < 0) | ||
804 | goto __error; | ||
805 | |||
806 | if (pdev) | ||
807 | pnp_set_drvdata(pdev, card); | ||
808 | else if (pcard) | ||
809 | pnp_set_card_drvdata(pcard, card); | ||
810 | else | ||
811 | snd_opl3sa2_legacy[dev] = card; | ||
812 | return 0; | ||
813 | |||
814 | __error: | ||
815 | snd_card_free(card); | ||
816 | return err; | ||
817 | } | 728 | } |
818 | 729 | ||
819 | #ifdef CONFIG_PNP | 730 | #ifdef CONFIG_PNP |
820 | static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, | 731 | static int __devinit snd_opl3sa2_pnp_detect(struct pnp_dev *pdev, |
821 | const struct pnp_device_id *id) | 732 | const struct pnp_device_id *id) |
822 | { | 733 | { |
823 | static int dev; | 734 | static int dev; |
824 | int res; | 735 | int err; |
736 | struct snd_card *card; | ||
825 | 737 | ||
826 | for ( ; dev < SNDRV_CARDS; dev++) { | 738 | if (pnp_device_is_isapnp(pdev)) |
827 | if (!enable[dev] || !isapnp[dev]) | 739 | return -ENOENT; /* we have another procedure - card */ |
828 | continue; | 740 | for (; dev < SNDRV_CARDS; dev++) { |
829 | res = snd_opl3sa2_probe(dev, pdev, NULL, NULL); | 741 | if (enable[dev] && isapnp[dev]) |
830 | if (res < 0) | 742 | break; |
831 | return res; | 743 | } |
832 | dev++; | 744 | if (dev >= SNDRV_CARDS) |
833 | return 0; | 745 | return -ENODEV; |
834 | } | 746 | |
835 | return -ENODEV; | 747 | card = snd_opl3sa2_card_new(dev); |
748 | if (! card) | ||
749 | return -ENOMEM; | ||
750 | if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { | ||
751 | snd_card_free(card); | ||
752 | return err; | ||
753 | } | ||
754 | snd_card_set_dev(card, &pdev->dev); | ||
755 | if ((err = snd_opl3sa2_probe(card, dev)) < 0) { | ||
756 | snd_card_free(card); | ||
757 | return err; | ||
758 | } | ||
759 | pnp_set_drvdata(pdev, card); | ||
760 | dev++; | ||
761 | return 0; | ||
836 | } | 762 | } |
837 | 763 | ||
838 | static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev) | 764 | static void __devexit snd_opl3sa2_pnp_remove(struct pnp_dev * pdev) |
839 | { | 765 | { |
840 | snd_card_t *card = (snd_card_t *) pnp_get_drvdata(pdev); | 766 | snd_card_free(pnp_get_drvdata(pdev)); |
841 | 767 | pnp_set_drvdata(pdev, NULL); | |
842 | snd_card_disconnect(card); | 768 | } |
843 | snd_card_free_in_thread(card); | 769 | |
770 | #ifdef CONFIG_PM | ||
771 | static int snd_opl3sa2_pnp_suspend(struct pnp_dev *pdev, pm_message_t state) | ||
772 | { | ||
773 | return snd_opl3sa2_suspend(pnp_get_drvdata(pdev), state); | ||
844 | } | 774 | } |
775 | static int snd_opl3sa2_pnp_resume(struct pnp_dev *pdev) | ||
776 | { | ||
777 | return snd_opl3sa2_resume(pnp_get_drvdata(pdev)); | ||
778 | } | ||
779 | #endif | ||
845 | 780 | ||
846 | static struct pnp_driver opl3sa2_pnp_driver = { | 781 | static struct pnp_driver opl3sa2_pnp_driver = { |
847 | .name = "opl3sa2-pnpbios", | 782 | .name = "opl3sa2-pnpbios", |
848 | .id_table = snd_opl3sa2_pnpbiosids, | 783 | .id_table = snd_opl3sa2_pnpbiosids, |
849 | .probe = snd_opl3sa2_pnp_detect, | 784 | .probe = snd_opl3sa2_pnp_detect, |
850 | .remove = __devexit_p(snd_opl3sa2_pnp_remove), | 785 | .remove = __devexit_p(snd_opl3sa2_pnp_remove), |
786 | #ifdef CONFIG_PM | ||
787 | .suspend = snd_opl3sa2_pnp_suspend, | ||
788 | .resume = snd_opl3sa2_pnp_resume, | ||
789 | #endif | ||
851 | }; | 790 | }; |
852 | 791 | ||
853 | static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card, | 792 | static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *pcard, |
854 | const struct pnp_card_device_id *id) | 793 | const struct pnp_card_device_id *id) |
855 | { | 794 | { |
856 | static int dev; | 795 | static int dev; |
857 | int res; | 796 | struct pnp_dev *pdev; |
797 | int err; | ||
798 | struct snd_card *card; | ||
858 | 799 | ||
859 | for ( ; dev < SNDRV_CARDS; dev++) { | 800 | pdev = pnp_request_card_device(pcard, id->devs[0].id, NULL); |
860 | if (!enable[dev]) | 801 | if (pdev == NULL) { |
861 | continue; | 802 | snd_printk(KERN_ERR PFX "can't get pnp device from id '%s'\n", |
862 | if (is_isapnp_selected(dev)) | 803 | id->devs[0].id); |
863 | continue; | 804 | return -EBUSY; |
864 | res = snd_opl3sa2_probe(dev, NULL, card, id); | 805 | } |
865 | if (res < 0) | 806 | for (; dev < SNDRV_CARDS; dev++) { |
866 | return res; | 807 | if (enable[dev] && isapnp[dev]) |
867 | dev++; | 808 | break; |
868 | return 0; | 809 | } |
869 | } | 810 | if (dev >= SNDRV_CARDS) |
870 | return -ENODEV; | 811 | return -ENODEV; |
812 | |||
813 | card = snd_opl3sa2_card_new(dev); | ||
814 | if (! card) | ||
815 | return -ENOMEM; | ||
816 | if ((err = snd_opl3sa2_pnp(dev, card->private_data, pdev)) < 0) { | ||
817 | snd_card_free(card); | ||
818 | return err; | ||
819 | } | ||
820 | snd_card_set_dev(card, &pdev->dev); | ||
821 | if ((err = snd_opl3sa2_probe(card, dev)) < 0) { | ||
822 | snd_card_free(card); | ||
823 | return err; | ||
824 | } | ||
825 | pnp_set_card_drvdata(pcard, card); | ||
826 | dev++; | ||
827 | return 0; | ||
871 | } | 828 | } |
872 | 829 | ||
873 | static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard) | 830 | static void __devexit snd_opl3sa2_pnp_cremove(struct pnp_card_link * pcard) |
874 | { | 831 | { |
875 | snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard); | 832 | snd_card_free(pnp_get_card_drvdata(pcard)); |
876 | 833 | pnp_set_card_drvdata(pcard, NULL); | |
877 | snd_card_disconnect(card); | ||
878 | snd_card_free_in_thread(card); | ||
879 | } | 834 | } |
880 | 835 | ||
836 | #ifdef CONFIG_PM | ||
837 | static int snd_opl3sa2_pnp_csuspend(struct pnp_card_link *pcard, pm_message_t state) | ||
838 | { | ||
839 | return snd_opl3sa2_suspend(pnp_get_card_drvdata(pcard), state); | ||
840 | } | ||
841 | static int snd_opl3sa2_pnp_cresume(struct pnp_card_link *pcard) | ||
842 | { | ||
843 | return snd_opl3sa2_resume(pnp_get_card_drvdata(pcard)); | ||
844 | } | ||
845 | #endif | ||
846 | |||
881 | static struct pnp_card_driver opl3sa2_pnpc_driver = { | 847 | static struct pnp_card_driver opl3sa2_pnpc_driver = { |
882 | .flags = PNP_DRIVER_RES_DISABLE, | 848 | .flags = PNP_DRIVER_RES_DISABLE, |
883 | .name = "opl3sa2", | 849 | .name = "opl3sa2", |
884 | .id_table = snd_opl3sa2_pnpids, | 850 | .id_table = snd_opl3sa2_pnpids, |
885 | .probe = snd_opl3sa2_pnp_cdetect, | 851 | .probe = snd_opl3sa2_pnp_cdetect, |
886 | .remove = __devexit_p(snd_opl3sa2_pnp_cremove), | 852 | .remove = __devexit_p(snd_opl3sa2_pnp_cremove), |
853 | #ifdef CONFIG_PM | ||
854 | .suspend = snd_opl3sa2_pnp_csuspend, | ||
855 | .resume = snd_opl3sa2_pnp_cresume, | ||
856 | #endif | ||
887 | }; | 857 | }; |
888 | #endif /* CONFIG_PNP */ | 858 | #endif /* CONFIG_PNP */ |
889 | 859 | ||
860 | static int __init snd_opl3sa2_nonpnp_probe(struct platform_device *pdev) | ||
861 | { | ||
862 | struct snd_card *card; | ||
863 | int err; | ||
864 | int dev = pdev->id; | ||
865 | |||
866 | if (port[dev] == SNDRV_AUTO_PORT) { | ||
867 | snd_printk(KERN_ERR PFX "specify port\n"); | ||
868 | return -EINVAL; | ||
869 | } | ||
870 | if (wss_port[dev] == SNDRV_AUTO_PORT) { | ||
871 | snd_printk(KERN_ERR PFX "specify wss_port\n"); | ||
872 | return -EINVAL; | ||
873 | } | ||
874 | if (fm_port[dev] == SNDRV_AUTO_PORT) { | ||
875 | snd_printk(KERN_ERR PFX "specify fm_port\n"); | ||
876 | return -EINVAL; | ||
877 | } | ||
878 | if (midi_port[dev] == SNDRV_AUTO_PORT) { | ||
879 | snd_printk(KERN_ERR PFX "specify midi_port\n"); | ||
880 | return -EINVAL; | ||
881 | } | ||
882 | |||
883 | card = snd_opl3sa2_card_new(dev); | ||
884 | if (! card) | ||
885 | return -ENOMEM; | ||
886 | snd_card_set_dev(card, &pdev->dev); | ||
887 | if ((err = snd_opl3sa2_probe(card, dev)) < 0) { | ||
888 | snd_card_free(card); | ||
889 | return err; | ||
890 | } | ||
891 | platform_set_drvdata(pdev, card); | ||
892 | return 0; | ||
893 | } | ||
894 | |||
895 | static int snd_opl3sa2_nonpnp_remove(struct platform_device *devptr) | ||
896 | { | ||
897 | snd_card_free(platform_get_drvdata(devptr)); | ||
898 | platform_set_drvdata(devptr, NULL); | ||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | #ifdef CONFIG_PM | ||
903 | static int snd_opl3sa2_nonpnp_suspend(struct platform_device *dev, pm_message_t state) | ||
904 | { | ||
905 | return snd_opl3sa2_suspend(platform_get_drvdata(dev), state); | ||
906 | } | ||
907 | |||
908 | static int snd_opl3sa2_nonpnp_resume(struct platform_device *dev) | ||
909 | { | ||
910 | return snd_opl3sa2_resume(platform_get_drvdata(dev)); | ||
911 | } | ||
912 | #endif | ||
913 | |||
914 | #define OPL3SA2_DRIVER "snd_opl3sa2" | ||
915 | |||
916 | static struct platform_driver snd_opl3sa2_nonpnp_driver = { | ||
917 | .probe = snd_opl3sa2_nonpnp_probe, | ||
918 | .remove = snd_opl3sa2_nonpnp_remove, | ||
919 | #ifdef CONFIG_PM | ||
920 | .suspend = snd_opl3sa2_nonpnp_suspend, | ||
921 | .resume = snd_opl3sa2_nonpnp_resume, | ||
922 | #endif | ||
923 | .driver = { | ||
924 | .name = OPL3SA2_DRIVER | ||
925 | }, | ||
926 | }; | ||
927 | |||
928 | static void __init_or_module snd_opl3sa2_unregister_all(void) | ||
929 | { | ||
930 | int i; | ||
931 | |||
932 | if (pnpc_registered) | ||
933 | pnp_unregister_card_driver(&opl3sa2_pnpc_driver); | ||
934 | if (pnp_registered) | ||
935 | pnp_unregister_driver(&opl3sa2_pnp_driver); | ||
936 | for (i = 0; i < ARRAY_SIZE(platform_devices); ++i) | ||
937 | platform_device_unregister(platform_devices[i]); | ||
938 | platform_driver_unregister(&snd_opl3sa2_nonpnp_driver); | ||
939 | } | ||
940 | |||
890 | static int __init alsa_card_opl3sa2_init(void) | 941 | static int __init alsa_card_opl3sa2_init(void) |
891 | { | 942 | { |
892 | int dev, cards = 0; | 943 | int i, err, cards = 0; |
893 | 944 | ||
894 | for (dev = 0; dev < SNDRV_CARDS; dev++) { | 945 | if ((err = platform_driver_register(&snd_opl3sa2_nonpnp_driver)) < 0) |
895 | if (!enable[dev]) | 946 | return err; |
896 | continue; | 947 | |
948 | for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { | ||
949 | struct platform_device *device; | ||
897 | #ifdef CONFIG_PNP | 950 | #ifdef CONFIG_PNP |
898 | if (isapnp[dev]) | 951 | if (isapnp[i]) |
899 | continue; | 952 | continue; |
900 | #endif | 953 | #endif |
901 | if (snd_opl3sa2_probe(dev, NULL, NULL, NULL) >= 0) | 954 | device = platform_device_register_simple(OPL3SA2_DRIVER, |
902 | cards++; | 955 | i, NULL, 0); |
956 | if (IS_ERR(device)) { | ||
957 | err = PTR_ERR(device); | ||
958 | goto errout; | ||
959 | } | ||
960 | platform_devices[i] = device; | ||
961 | cards++; | ||
903 | } | 962 | } |
904 | #ifdef CONFIG_PNP | 963 | |
905 | cards += pnp_register_driver(&opl3sa2_pnp_driver); | 964 | err = pnp_register_driver(&opl3sa2_pnp_driver); |
906 | cards += pnp_register_card_driver(&opl3sa2_pnpc_driver); | 965 | if (err >= 0) { |
907 | #endif | 966 | pnp_registered = 1; |
967 | cards += err; | ||
968 | } | ||
969 | err = pnp_register_card_driver(&opl3sa2_pnpc_driver); | ||
970 | if (err >= 0) { | ||
971 | pnpc_registered = 1; | ||
972 | cards += err; | ||
973 | } | ||
974 | |||
908 | if (!cards) { | 975 | if (!cards) { |
909 | #ifdef MODULE | 976 | #ifdef MODULE |
910 | snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); | 977 | snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); |
911 | #endif | 978 | #endif |
912 | #ifdef CONFIG_PNP | 979 | err = -ENODEV; |
913 | pnp_unregister_card_driver(&opl3sa2_pnpc_driver); | 980 | goto errout; |
914 | pnp_unregister_driver(&opl3sa2_pnp_driver); | ||
915 | #endif | ||
916 | return -ENODEV; | ||
917 | } | 981 | } |
918 | return 0; | 982 | return 0; |
983 | |||
984 | errout: | ||
985 | snd_opl3sa2_unregister_all(); | ||
986 | return err; | ||
919 | } | 987 | } |
920 | 988 | ||
921 | static void __exit alsa_card_opl3sa2_exit(void) | 989 | static void __exit alsa_card_opl3sa2_exit(void) |
922 | { | 990 | { |
923 | int idx; | 991 | snd_opl3sa2_unregister_all(); |
924 | |||
925 | #ifdef CONFIG_PNP | ||
926 | /* PnP cards first */ | ||
927 | pnp_unregister_card_driver(&opl3sa2_pnpc_driver); | ||
928 | pnp_unregister_driver(&opl3sa2_pnp_driver); | ||
929 | #endif | ||
930 | for (idx = 0; idx < SNDRV_CARDS; idx++) | ||
931 | snd_card_free(snd_opl3sa2_legacy[idx]); | ||
932 | } | 992 | } |
933 | 993 | ||
934 | module_init(alsa_card_opl3sa2_init) | 994 | module_init(alsa_card_opl3sa2_init) |