aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/cs423x/cs4236.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/isa/cs423x/cs4236.c')
-rw-r--r--sound/isa/cs423x/cs4236.c591
1 files changed, 404 insertions, 187 deletions
diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c
index d60a55e6a0b1..e1683337e6cd 100644
--- a/sound/isa/cs423x/cs4236.c
+++ b/sound/isa/cs423x/cs4236.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/slab.h> 26#include <linux/slab.h>
25#include <linux/pnp.h> 27#include <linux/pnp.h>
26#include <linux/moduleparam.h> 28#include <linux/moduleparam.h>
@@ -122,7 +124,14 @@ MODULE_PARM_DESC(dma1, "DMA1 # for " IDENT " driver.");
122module_param_array(dma2, int, NULL, 0444); 124module_param_array(dma2, int, NULL, 0444);
123MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver."); 125MODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
124 126
127static struct platform_device *platform_devices[SNDRV_CARDS];
128static int pnpc_registered;
129#ifdef CS4232
130static int pnp_registered;
131#endif
132
125struct snd_card_cs4236 { 133struct snd_card_cs4236 {
134 struct snd_cs4231 *chip;
126 struct resource *res_sb_port; 135 struct resource *res_sb_port;
127#ifdef CONFIG_PNP 136#ifdef CONFIG_PNP
128 struct pnp_dev *wss; 137 struct pnp_dev *wss;
@@ -131,33 +140,26 @@ struct snd_card_cs4236 {
131#endif 140#endif
132}; 141};
133 142
134static snd_card_t *snd_cs4236_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
135
136#ifdef CONFIG_PNP 143#ifdef CONFIG_PNP
137 144
138#define ISAPNP_CS4232(_va, _vb, _vc, _device, _wss, _ctrl, _mpu401) \ 145#ifdef CS4232
139 { \ 146/*
140 ISAPNP_CARD_ID(_va, _vb, _vc, _device), \ 147 * PNP BIOS
141 .devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _wss), \ 148 */
142 ISAPNP_DEVICE_ID(_va, _vb, _vc, _ctrl), \ 149static const struct pnp_device_id snd_cs4232_pnpbiosids[] = {
143 ISAPNP_DEVICE_ID(_va, _vb, _vc, _mpu401) } \ 150 { .id = "CSC0100" },
144 } 151 { .id = "CSC0000" },
145#define ISAPNP_CS4232_1(_va, _vb, _vc, _device, _wss, _ctrl, _mpu401) \ 152 /* Guillemot Turtlebeach something appears to be cs4232 compatible
146 { \ 153 * (untested) */
147 ISAPNP_CARD_ID(_va, _vb, _vc, _device), \ 154 { .id = "GIM0100" },
148 .devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _wss), \ 155 { .id = "" }
149 ISAPNP_DEVICE_ID(_va, _vb, _vc, _ctrl), \ 156};
150 ISAPNP_DEVICE_ID('P', 'N', 'P', _mpu401) } \ 157MODULE_DEVICE_TABLE(pnp, snd_cs4232_pnpbiosids);
151 } 158#endif /* CS4232 */
152#define ISAPNP_CS4232_WOMPU(_va, _vb, _vc, _device, _wss, _ctrl) \
153 { \
154 ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
155 .devs = { ISAPNP_DEVICE_ID(_va, _vb, _vc, _wss), \
156 ISAPNP_DEVICE_ID(_va, _vb, _vc, _ctrl) } \
157 }
158
159 159
160#ifdef CS4232 160#ifdef CS4232
161#define CS423X_DRIVER "snd_cs4232"
162#define CS423X_ISAPNP_DRIVER "cs4232_isapnp"
161static struct pnp_card_device_id snd_cs423x_pnpids[] = { 163static struct pnp_card_device_id snd_cs423x_pnpids[] = {
162 /* Philips PCA70PS */ 164 /* Philips PCA70PS */
163 { .id = "CSC0d32", .devs = { { "CSC0000" }, { "CSC0010" }, { "PNPb006" } } }, 165 { .id = "CSC0d32", .devs = { { "CSC0000" }, { "CSC0010" }, { "PNPb006" } } },
@@ -177,6 +179,8 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
177 { .id = "" } /* end */ 179 { .id = "" } /* end */
178}; 180};
179#else /* CS4236 */ 181#else /* CS4236 */
182#define CS423X_DRIVER "snd_cs4236"
183#define CS423X_ISAPNP_DRIVER "cs4236_isapnp"
180static struct pnp_card_device_id snd_cs423x_pnpids[] = { 184static struct pnp_card_device_id snd_cs423x_pnpids[] = {
181 /* Intel Marlin Spike Motherboard - CS4235 */ 185 /* Intel Marlin Spike Motherboard - CS4235 */
182 { .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, 186 { .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
@@ -261,37 +265,12 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = {
261 265
262MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids); 266MODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
263 267
264static int __devinit snd_card_cs4236_pnp(int dev, struct snd_card_cs4236 *acard, 268/* WSS initialization */
265 struct pnp_card_link *card, 269static int __devinit snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev,
266 const struct pnp_card_device_id *id) 270 struct pnp_resource_table *cfg)
267{ 271{
268 struct pnp_dev *pdev;
269 struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
270 int err; 272 int err;
271 273
272 if (!cfg)
273 return -ENOMEM;
274
275 acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
276 if (acard->wss == NULL) {
277 kfree(cfg);
278 return -EBUSY;
279 }
280 acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL);
281 if (acard->ctrl == NULL) {
282 kfree(cfg);
283 return -EBUSY;
284 }
285 if (id->devs[2].id[0]) {
286 acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
287 if (acard->mpu == NULL) {
288 kfree(cfg);
289 return -EBUSY;
290 }
291 }
292
293 /* WSS initialization */
294 pdev = acard->wss;
295 pnp_init_resource_table(cfg); 274 pnp_init_resource_table(cfg);
296 if (port[dev] != SNDRV_AUTO_PORT) 275 if (port[dev] != SNDRV_AUTO_PORT)
297 pnp_resource_change(&cfg->port_resource[0], port[dev], 4); 276 pnp_resource_change(&cfg->port_resource[0], port[dev], 4);
@@ -310,7 +289,6 @@ static int __devinit snd_card_cs4236_pnp(int dev, struct snd_card_cs4236 *acard,
310 snd_printk(KERN_ERR IDENT " WSS PnP manual resources are invalid, using auto config\n"); 289 snd_printk(KERN_ERR IDENT " WSS PnP manual resources are invalid, using auto config\n");
311 err = pnp_activate_dev(pdev); 290 err = pnp_activate_dev(pdev);
312 if (err < 0) { 291 if (err < 0) {
313 kfree(cfg);
314 printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n"); 292 printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n");
315 return -EBUSY; 293 return -EBUSY;
316 } 294 }
@@ -325,63 +303,124 @@ static int __devinit snd_card_cs4236_pnp(int dev, struct snd_card_cs4236 *acard,
325 port[dev], fm_port[dev], sb_port[dev]); 303 port[dev], fm_port[dev], sb_port[dev]);
326 snd_printdd("isapnp WSS: irq=%i, dma1=%i, dma2=%i\n", 304 snd_printdd("isapnp WSS: irq=%i, dma1=%i, dma2=%i\n",
327 irq[dev], dma1[dev], dma2[dev]); 305 irq[dev], dma1[dev], dma2[dev]);
328 /* CTRL initialization */ 306 return 0;
329 if (acard->ctrl && cport[dev] > 0) { 307}
330 pdev = acard->ctrl; 308
331 pnp_init_resource_table(cfg); 309/* CTRL initialization */
332 if (cport[dev] != SNDRV_AUTO_PORT) 310static int __devinit snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev,
333 pnp_resource_change(&cfg->port_resource[0], cport[dev], 8); 311 struct pnp_resource_table *cfg)
334 err = pnp_manual_config_dev(pdev, cfg, 0); 312{
335 if (err < 0) 313 int err;
336 snd_printk(KERN_ERR IDENT " CTRL PnP manual resources are invalid, using auto config\n"); 314
337 err = pnp_activate_dev(pdev); 315 pnp_init_resource_table(cfg);
338 if (err < 0) { 316 if (cport[dev] != SNDRV_AUTO_PORT)
339 kfree(cfg); 317 pnp_resource_change(&cfg->port_resource[0], cport[dev], 8);
340 printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n"); 318 err = pnp_manual_config_dev(pdev, cfg, 0);
341 return -EBUSY; 319 if (err < 0)
342 } 320 snd_printk(KERN_ERR IDENT " CTRL PnP manual resources are invalid, using auto config\n");
343 cport[dev] = pnp_port_start(pdev, 0); 321 err = pnp_activate_dev(pdev);
344 snd_printdd("isapnp CTRL: control port=0x%lx\n", cport[dev]); 322 if (err < 0) {
323 printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n");
324 return -EBUSY;
345 } 325 }
346 /* MPU initialization */ 326 cport[dev] = pnp_port_start(pdev, 0);
347 if (acard->mpu && mpu_port[dev] > 0) { 327 snd_printdd("isapnp CTRL: control port=0x%lx\n", cport[dev]);
348 pdev = acard->mpu; 328 return 0;
349 pnp_init_resource_table(cfg); 329}
350 if (mpu_port[dev] != SNDRV_AUTO_PORT) 330
351 pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2); 331/* MPU initialization */
352 if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0) 332static int __devinit snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev,
353 pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1); 333 struct pnp_resource_table *cfg)
354 err = pnp_manual_config_dev(pdev, cfg, 0); 334{
355 if (err < 0) 335 int err;
356 snd_printk(KERN_ERR IDENT " MPU401 PnP manual resources are invalid, using auto config\n"); 336
357 err = pnp_activate_dev(pdev); 337 pnp_init_resource_table(cfg);
358 if (err < 0) { 338 if (mpu_port[dev] != SNDRV_AUTO_PORT)
359 printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n"); 339 pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
360 mpu_port[dev] = SNDRV_AUTO_PORT; 340 if (mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] >= 0)
361 mpu_irq[dev] = SNDRV_AUTO_IRQ; 341 pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
342 err = pnp_manual_config_dev(pdev, cfg, 0);
343 if (err < 0)
344 snd_printk(KERN_ERR IDENT " MPU401 PnP manual resources are invalid, using auto config\n");
345 err = pnp_activate_dev(pdev);
346 if (err < 0) {
347 printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n");
348 mpu_port[dev] = SNDRV_AUTO_PORT;
349 mpu_irq[dev] = SNDRV_AUTO_IRQ;
350 } else {
351 mpu_port[dev] = pnp_port_start(pdev, 0);
352 if (mpu_irq[dev] >= 0 &&
353 pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) {
354 mpu_irq[dev] = pnp_irq(pdev, 0);
362 } else { 355 } else {
363 mpu_port[dev] = pnp_port_start(pdev, 0); 356 mpu_irq[dev] = -1; /* disable interrupt */
364 if (mpu_irq[dev] >= 0 &&
365 pnp_irq_valid(pdev, 0) && pnp_irq(pdev, 0) >= 0) {
366 mpu_irq[dev] = pnp_irq(pdev, 0);
367 } else {
368 mpu_irq[dev] = -1; /* disable interrupt */
369 }
370 } 357 }
371 snd_printdd("isapnp MPU: port=0x%lx, irq=%i\n", mpu_port[dev], mpu_irq[dev]); 358 }
359 snd_printdd("isapnp MPU: port=0x%lx, irq=%i\n", mpu_port[dev], mpu_irq[dev]);
360 return 0;
361}
362
363#ifdef CS4232
364static int __devinit snd_card_cs4232_pnp(int dev, struct snd_card_cs4236 *acard,
365 struct pnp_dev *pdev)
366{
367 struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
368
369 if (!cfg)
370 return -ENOMEM;
371 if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0) {
372 kfree(cfg);
373 return -EBUSY;
372 } 374 }
373 kfree(cfg); 375 kfree(cfg);
376 cport[dev] = -1;
374 return 0; 377 return 0;
375} 378}
376#endif /* CONFIG_PNP */ 379#endif
377 380
378static void snd_card_cs4236_free(snd_card_t *card) 381static int __devinit snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
382 struct pnp_card_link *card,
383 const struct pnp_card_device_id *id)
379{ 384{
380 struct snd_card_cs4236 *acard = (struct snd_card_cs4236 *)card->private_data; 385 struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
386
387 if (!cfg)
388 return -ENOMEM;
389
390 acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
391 if (acard->wss == NULL)
392 goto error;
393 acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL);
394 if (acard->ctrl == NULL)
395 goto error;
396 if (id->devs[2].id[0]) {
397 acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
398 if (acard->mpu == NULL)
399 goto error;
400 }
381 401
382 if (acard) 402 /* WSS initialization */
383 release_and_free_resource(acard->res_sb_port); 403 if (snd_cs423x_pnp_init_wss(dev, acard->wss, cfg) < 0)
404 goto error;
405
406 /* CTRL initialization */
407 if (acard->ctrl && cport[dev] > 0) {
408 if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl, cfg) < 0)
409 goto error;
410 }
411 /* MPU initialization */
412 if (acard->mpu && mpu_port[dev] > 0) {
413 if (snd_cs423x_pnp_init_mpu(dev, acard->ctrl, cfg) < 0)
414 goto error;
415 }
416 kfree(cfg);
417 return 0;
418
419 error:
420 kfree(cfg);
421 return -EBUSY;
384} 422}
423#endif /* CONFIG_PNP */
385 424
386#ifdef CONFIG_PNP 425#ifdef CONFIG_PNP
387#define is_isapnp_selected(dev) isapnp[dev] 426#define is_isapnp_selected(dev) isapnp[dev]
@@ -389,46 +428,38 @@ static void snd_card_cs4236_free(snd_card_t *card)
389#define is_isapnp_selected(dev) 0 428#define is_isapnp_selected(dev) 0
390#endif 429#endif
391 430
392static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, 431static void snd_card_cs4236_free(struct snd_card *card)
393 const struct pnp_card_device_id *pid)
394{ 432{
395 snd_card_t *card; 433 struct snd_card_cs4236 *acard = card->private_data;
396 struct snd_card_cs4236 *acard; 434
397 snd_pcm_t *pcm = NULL; 435 release_and_free_resource(acard->res_sb_port);
398 cs4231_t *chip; 436}
399 opl3_t *opl3; 437
400 int err; 438static struct snd_card *snd_cs423x_card_new(int dev)
439{
440 struct snd_card *card;
401 441
402 if (! is_isapnp_selected(dev)) {
403 if (port[dev] == SNDRV_AUTO_PORT) {
404 snd_printk(KERN_ERR "specify port\n");
405 return -EINVAL;
406 }
407 if (cport[dev] == SNDRV_AUTO_PORT) {
408 snd_printk(KERN_ERR "specify cport\n");
409 return -EINVAL;
410 }
411 }
412 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 442 card = snd_card_new(index[dev], id[dev], THIS_MODULE,
413 sizeof(struct snd_card_cs4236)); 443 sizeof(struct snd_card_cs4236));
414 if (card == NULL) 444 if (card == NULL)
415 return -ENOMEM; 445 return NULL;
416 acard = (struct snd_card_cs4236 *)card->private_data;
417 card->private_free = snd_card_cs4236_free; 446 card->private_free = snd_card_cs4236_free;
418#ifdef CONFIG_PNP 447 return card;
419 if (isapnp[dev]) { 448}
420 if ((err = snd_card_cs4236_pnp(dev, acard, pcard, pid))<0) { 449
421 printk(KERN_ERR "isapnp detection failed and probing for " IDENT " is not supported\n"); 450static int __devinit snd_cs423x_probe(struct snd_card *card, int dev)
422 goto _err; 451{
423 } 452 struct snd_card_cs4236 *acard;
424 snd_card_set_dev(card, &pcard->card->dev); 453 struct snd_pcm *pcm;
425 } 454 struct snd_cs4231 *chip;
426#endif 455 struct snd_opl3 *opl3;
456 int err;
457
458 acard = card->private_data;
427 if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) 459 if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT)
428 if ((acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB")) == NULL) { 460 if ((acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB")) == NULL) {
429 printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]); 461 printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]);
430 err = -EBUSY; 462 return -EBUSY;
431 goto _err;
432 } 463 }
433 464
434#ifdef CS4232 465#ifdef CS4232
@@ -441,13 +472,14 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard,
441 CS4231_HW_DETECT, 472 CS4231_HW_DETECT,
442 0, 473 0,
443 &chip)) < 0) 474 &chip)) < 0)
444 goto _err; 475 return err;
476 acard->chip = chip;
445 477
446 if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) 478 if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0)
447 goto _err; 479 return err;
448 480
449 if ((err = snd_cs4231_mixer(chip)) < 0) 481 if ((err = snd_cs4231_mixer(chip)) < 0)
450 goto _err; 482 return err;
451 483
452#else /* CS4236 */ 484#else /* CS4236 */
453 if ((err = snd_cs4236_create(card, 485 if ((err = snd_cs4236_create(card,
@@ -459,13 +491,14 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard,
459 CS4231_HW_DETECT, 491 CS4231_HW_DETECT,
460 0, 492 0,
461 &chip)) < 0) 493 &chip)) < 0)
462 goto _err; 494 return err;
495 acard->chip = chip;
463 496
464 if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0) 497 if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0)
465 goto _err; 498 return err;
466 499
467 if ((err = snd_cs4236_mixer(chip)) < 0) 500 if ((err = snd_cs4236_mixer(chip)) < 0)
468 goto _err; 501 return err;
469#endif 502#endif
470 strcpy(card->driver, pcm->name); 503 strcpy(card->driver, pcm->name);
471 strcpy(card->shortname, pcm->name); 504 strcpy(card->shortname, pcm->name);
@@ -478,7 +511,7 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard,
478 sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); 511 sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]);
479 512
480 if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) 513 if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0)
481 goto _err; 514 return err;
482 515
483 if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { 516 if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
484 if (snd_opl3_create(card, 517 if (snd_opl3_create(card,
@@ -487,7 +520,7 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard,
487 printk(KERN_WARNING IDENT ": OPL3 not detected\n"); 520 printk(KERN_WARNING IDENT ": OPL3 not detected\n");
488 } else { 521 } else {
489 if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) 522 if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0)
490 goto _err; 523 return err;
491 } 524 }
492 } 525 }
493 526
@@ -501,95 +534,279 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard,
501 printk(KERN_WARNING IDENT ": MPU401 not detected\n"); 534 printk(KERN_WARNING IDENT ": MPU401 not detected\n");
502 } 535 }
503 536
504 if ((err = snd_card_set_generic_dev(card)) < 0) 537 return snd_card_register(card);
505 goto _err; 538}
506 539
507 if ((err = snd_card_register(card)) < 0) 540static int __init snd_cs423x_nonpnp_probe(struct platform_device *pdev)
508 goto _err; 541{
509 if (pcard) 542 int dev = pdev->id;
510 pnp_set_card_drvdata(pcard, card); 543 struct snd_card *card;
511 else 544 int err;
512 snd_cs4236_legacy[dev] = card; 545
546 if (port[dev] == SNDRV_AUTO_PORT) {
547 snd_printk(KERN_ERR "specify port\n");
548 return -EINVAL;
549 }
550 if (cport[dev] == SNDRV_AUTO_PORT) {
551 snd_printk(KERN_ERR "specify cport\n");
552 return -EINVAL;
553 }
554
555 card = snd_cs423x_card_new(dev);
556 if (! card)
557 return -ENOMEM;
558 snd_card_set_dev(card, &pdev->dev);
559 if ((err = snd_cs423x_probe(card, dev)) < 0) {
560 snd_card_free(card);
561 return err;
562 }
563
564 platform_set_drvdata(pdev, card);
513 return 0; 565 return 0;
566}
514 567
515 _err: 568static int __devexit snd_cs423x_nonpnp_remove(struct platform_device *devptr)
516 snd_card_free(card); 569{
517 return err; 570 snd_card_free(platform_get_drvdata(devptr));
571 platform_set_drvdata(devptr, NULL);
572 return 0;
518} 573}
519 574
575#ifdef CONFIG_PM
576static int snd_cs423x_suspend(struct snd_card *card)
577{
578 struct snd_card_cs4236 *acard = card->private_data;
579 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
580 acard->chip->suspend(acard->chip);
581 return 0;
582}
583
584static int snd_cs423x_resume(struct snd_card *card)
585{
586 struct snd_card_cs4236 *acard = card->private_data;
587 acard->chip->resume(acard->chip);
588 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
589 return 0;
590}
591
592static int snd_cs423x_nonpnp_suspend(struct platform_device *dev, pm_message_t state)
593{
594 return snd_cs423x_suspend(platform_get_drvdata(dev));
595}
596
597static int snd_cs423x_nonpnp_resume(struct platform_device *dev)
598{
599 return snd_cs423x_resume(platform_get_drvdata(dev));
600}
601#endif
602
603static struct platform_driver cs423x_nonpnp_driver = {
604 .probe = snd_cs423x_nonpnp_probe,
605 .remove = __devexit_p(snd_cs423x_nonpnp_remove),
606#ifdef CONFIG_PM
607 .suspend = snd_cs423x_nonpnp_suspend,
608 .resume = snd_cs423x_nonpnp_resume,
609#endif
610 .driver = {
611 .name = CS423X_DRIVER
612 },
613};
614
615
520#ifdef CONFIG_PNP 616#ifdef CONFIG_PNP
521static int __devinit snd_cs423x_pnp_detect(struct pnp_card_link *card, 617#ifdef CS4232
522 const struct pnp_card_device_id *id) 618static int __devinit snd_cs4232_pnpbios_detect(struct pnp_dev *pdev,
619 const struct pnp_device_id *id)
523{ 620{
524 static int dev; 621 static int dev;
622 int err;
623 struct snd_card *card;
624
625 if (pnp_device_is_isapnp(pdev))
626 return -ENOENT; /* we have another procedure - card */
627 for (; dev < SNDRV_CARDS; dev++) {
628 if (enable[dev] && isapnp[dev])
629 break;
630 }
631 if (dev >= SNDRV_CARDS)
632 return -ENODEV;
633
634 card = snd_cs423x_card_new(dev);
635 if (! card)
636 return -ENOMEM;
637 if ((err = snd_card_cs4232_pnp(dev, card->private_data, pdev)) < 0) {
638 printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
639 snd_card_free(card);
640 return err;
641 }
642 snd_card_set_dev(card, &pdev->dev);
643 if ((err = snd_cs423x_probe(card, dev)) < 0) {
644 snd_card_free(card);
645 return err;
646 }
647 pnp_set_drvdata(pdev, card);
648 dev++;
649 return 0;
650}
651
652static void __devexit snd_cs4232_pnp_remove(struct pnp_dev * pdev)
653{
654 snd_card_free(pnp_get_drvdata(pdev));
655 pnp_set_drvdata(pdev, NULL);
656}
657
658#ifdef CONFIG_PM
659static int snd_cs4232_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
660{
661 return snd_cs423x_suspend(pnp_get_drvdata(pdev));
662}
663
664static int snd_cs4232_pnp_resume(struct pnp_dev *pdev)
665{
666 return snd_cs423x_resume(pnp_get_drvdata(pdev));
667}
668#endif
669
670static struct pnp_driver cs4232_pnp_driver = {
671 .name = "cs4232-pnpbios",
672 .id_table = snd_cs4232_pnpbiosids,
673 .probe = snd_cs4232_pnpbios_detect,
674 .remove = __devexit_p(snd_cs4232_pnp_remove),
675#ifdef CONFIG_PM
676 .suspend = snd_cs4232_pnp_suspend,
677 .resume = snd_cs4232_pnp_resume,
678#endif
679};
680#endif /* CS4232 */
681
682static int __devinit snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
683 const struct pnp_card_device_id *pid)
684{
685 static int dev;
686 struct snd_card *card;
525 int res; 687 int res;
526 688
527 for ( ; dev < SNDRV_CARDS; dev++) { 689 for ( ; dev < SNDRV_CARDS; dev++) {
528 if (!enable[dev] || !isapnp[dev]) 690 if (enable[dev] && isapnp[dev])
529 continue; 691 break;
530 res = snd_card_cs423x_probe(dev, card, id); 692 }
531 if (res < 0) 693 if (dev >= SNDRV_CARDS)
532 return res; 694 return -ENODEV;
533 dev++; 695
534 return 0; 696 card = snd_cs423x_card_new(dev);
697 if (! card)
698 return -ENOMEM;
699 if ((res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid)) < 0) {
700 printk(KERN_ERR "isapnp detection failed and probing for " IDENT
701 " is not supported\n");
702 snd_card_free(card);
703 return res;
704 }
705 snd_card_set_dev(card, &pcard->card->dev);
706 if ((res = snd_cs423x_probe(card, dev)) < 0) {
707 snd_card_free(card);
708 return res;
535 } 709 }
536 return -ENODEV; 710 pnp_set_card_drvdata(pcard, card);
711 dev++;
712 return 0;
537} 713}
538 714
539static void __devexit snd_cs423x_pnp_remove(struct pnp_card_link * pcard) 715static void __devexit snd_cs423x_pnpc_remove(struct pnp_card_link * pcard)
540{ 716{
541 snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard); 717 snd_card_free(pnp_get_card_drvdata(pcard));
542 718 pnp_set_card_drvdata(pcard, NULL);
543 snd_card_disconnect(card);
544 snd_card_free_in_thread(card);
545} 719}
546 720
721#ifdef CONFIG_PM
722static int snd_cs423x_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
723{
724 return snd_cs423x_suspend(pnp_get_card_drvdata(pcard));
725}
726
727static int snd_cs423x_pnpc_resume(struct pnp_card_link *pcard)
728{
729 return snd_cs423x_resume(pnp_get_card_drvdata(pcard));
730}
731#endif
732
547static struct pnp_card_driver cs423x_pnpc_driver = { 733static struct pnp_card_driver cs423x_pnpc_driver = {
548 .flags = PNP_DRIVER_RES_DISABLE, 734 .flags = PNP_DRIVER_RES_DISABLE,
549 .name = "cs423x", 735 .name = CS423X_ISAPNP_DRIVER,
550 .id_table = snd_cs423x_pnpids, 736 .id_table = snd_cs423x_pnpids,
551 .probe = snd_cs423x_pnp_detect, 737 .probe = snd_cs423x_pnpc_detect,
552 .remove = __devexit_p(snd_cs423x_pnp_remove), 738 .remove = __devexit_p(snd_cs423x_pnpc_remove),
739#ifdef CONFIG_PM
740 .suspend = snd_cs423x_pnpc_suspend,
741 .resume = snd_cs423x_pnpc_resume,
742#endif
553}; 743};
554#endif /* CONFIG_PNP */ 744#endif /* CONFIG_PNP */
555 745
746static void __init_or_module snd_cs423x_unregister_all(void)
747{
748 int i;
749
750 if (pnpc_registered)
751 pnp_unregister_card_driver(&cs423x_pnpc_driver);
752#ifdef CS4232
753 if (pnp_registered)
754 pnp_unregister_driver(&cs4232_pnp_driver);
755#endif
756 for (i = 0; i < ARRAY_SIZE(platform_devices); ++i)
757 platform_device_unregister(platform_devices[i]);
758 platform_driver_unregister(&cs423x_nonpnp_driver);
759}
760
556static int __init alsa_card_cs423x_init(void) 761static int __init alsa_card_cs423x_init(void)
557{ 762{
558 int dev, cards = 0; 763 int i, err, cards = 0;
559 764
560 for (dev = 0; dev < SNDRV_CARDS; dev++) { 765 if ((err = platform_driver_register(&cs423x_nonpnp_driver)) < 0)
561 if (!enable[dev]) 766 return err;
562 continue; 767
563 if (is_isapnp_selected(dev)) 768 for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
769 struct platform_device *device;
770 if (is_isapnp_selected(i))
564 continue; 771 continue;
565 if (snd_card_cs423x_probe(dev, NULL, NULL) >= 0) 772 device = platform_device_register_simple(CS423X_DRIVER,
566 cards++; 773 i, NULL, 0);
774 if (IS_ERR(device)) {
775 err = PTR_ERR(device);
776 goto errout;
777 }
778 platform_devices[i] = device;
779 cards++;
780 }
781#ifdef CS4232
782 i = pnp_register_driver(&cs4232_pnp_driver);
783 if (i >= 0) {
784 pnp_registered = 1;
785 cards += i;
567 } 786 }
568#ifdef CONFIG_PNP
569 cards += pnp_register_card_driver(&cs423x_pnpc_driver);
570#endif 787#endif
788 i = pnp_register_card_driver(&cs423x_pnpc_driver);
789 if (i >= 0) {
790 pnpc_registered = 1;
791 cards += i;
792 }
571 if (!cards) { 793 if (!cards) {
572#ifdef CONFIG_PNP
573 pnp_unregister_card_driver(&cs423x_pnpc_driver);
574#endif
575#ifdef MODULE 794#ifdef MODULE
576 printk(KERN_ERR IDENT " soundcard not found or device busy\n"); 795 printk(KERN_ERR IDENT " soundcard not found or device busy\n");
577#endif 796#endif
578 return -ENODEV; 797 err = -ENODEV;
798 goto errout;
579 } 799 }
580 return 0; 800 return 0;
801
802 errout:
803 snd_cs423x_unregister_all();
804 return err;
581} 805}
582 806
583static void __exit alsa_card_cs423x_exit(void) 807static void __exit alsa_card_cs423x_exit(void)
584{ 808{
585 int idx; 809 snd_cs423x_unregister_all();
586
587#ifdef CONFIG_PNP
588 /* PnP cards first */
589 pnp_unregister_card_driver(&cs423x_pnpc_driver);
590#endif
591 for (idx = 0; idx < SNDRV_CARDS; idx++)
592 snd_card_free(snd_cs4236_legacy[idx]);
593} 810}
594 811
595module_init(alsa_card_cs423x_init) 812module_init(alsa_card_cs423x_init)