aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa/sc6000.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/isa/sc6000.c')
-rw-r--r--sound/isa/sc6000.c127
1 files changed, 99 insertions, 28 deletions
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 782010608ef4..983ab7e3b5b4 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -2,6 +2,8 @@
2 * Driver for Gallant SC-6000 soundcard. This card is also known as 2 * Driver for Gallant SC-6000 soundcard. This card is also known as
3 * Audio Excel DSP 16 or Zoltrix AV302. 3 * Audio Excel DSP 16 or Zoltrix AV302.
4 * These cards use CompuMedia ASC-9308 chip + AD1848 codec. 4 * These cards use CompuMedia ASC-9308 chip + AD1848 codec.
5 * SC-6600 and SC-7000 cards are also supported. They are based on
6 * CompuMedia ASC-9408 chip and CS4231 codec.
5 * 7 *
6 * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> 8 * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
7 * 9 *
@@ -191,7 +193,7 @@ static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq)
191 return val; 193 return val;
192} 194}
193 195
194static __devinit int sc6000_wait_data(char __iomem *vport) 196static int sc6000_wait_data(char __iomem *vport)
195{ 197{
196 int loop = 1000; 198 int loop = 1000;
197 unsigned char val = 0; 199 unsigned char val = 0;
@@ -206,7 +208,7 @@ static __devinit int sc6000_wait_data(char __iomem *vport)
206 return -EAGAIN; 208 return -EAGAIN;
207} 209}
208 210
209static __devinit int sc6000_read(char __iomem *vport) 211static int sc6000_read(char __iomem *vport)
210{ 212{
211 if (sc6000_wait_data(vport)) 213 if (sc6000_wait_data(vport))
212 return -EBUSY; 214 return -EBUSY;
@@ -215,7 +217,7 @@ static __devinit int sc6000_read(char __iomem *vport)
215 217
216} 218}
217 219
218static __devinit int sc6000_write(char __iomem *vport, int cmd) 220static int sc6000_write(char __iomem *vport, int cmd)
219{ 221{
220 unsigned char val; 222 unsigned char val;
221 int loop = 500000; 223 int loop = 500000;
@@ -276,8 +278,33 @@ static int __devinit sc6000_dsp_reset(char __iomem *vport)
276} 278}
277 279
278/* detection and initialization */ 280/* detection and initialization */
279static int __devinit sc6000_cfg_write(char __iomem *vport, 281static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg)
280 unsigned char softcfg) 282{
283 if (sc6000_write(vport, COMMAND_6C) < 0) {
284 snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C);
285 return -EIO;
286 }
287 if (sc6000_write(vport, COMMAND_5C) < 0) {
288 snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C);
289 return -EIO;
290 }
291 if (sc6000_write(vport, cfg[0]) < 0) {
292 snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]);
293 return -EIO;
294 }
295 if (sc6000_write(vport, cfg[1]) < 0) {
296 snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]);
297 return -EIO;
298 }
299 if (sc6000_write(vport, COMMAND_C5) < 0) {
300 snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5);
301 return -EIO;
302 }
303
304 return 0;
305}
306
307static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg)
281{ 308{
282 309
283 if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { 310 if (sc6000_write(vport, WRITE_MDIRQ_CFG)) {
@@ -291,7 +318,7 @@ static int __devinit sc6000_cfg_write(char __iomem *vport,
291 return 0; 318 return 0;
292} 319}
293 320
294static int __devinit sc6000_setup_board(char __iomem *vport, int config) 321static int sc6000_setup_board(char __iomem *vport, int config)
295{ 322{
296 int loop = 10; 323 int loop = 10;
297 324
@@ -334,16 +361,38 @@ static int __devinit sc6000_init_mss(char __iomem *vport, int config,
334 return 0; 361 return 0;
335} 362}
336 363
337static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, 364static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg,
338 char __iomem *vmss_port, int mpu_irq) 365 long xport, long xmpu,
366 long xmss_port)
367{
368 cfg[0] = 0;
369 cfg[1] = 0;
370 if (xport == 0x240)
371 cfg[0] |= 1;
372 if (xmpu != SNDRV_AUTO_PORT) {
373 cfg[0] |= (xmpu & 0x30) >> 2;
374 cfg[1] |= 0x20;
375 }
376 if (xmss_port == 0xe80)
377 cfg[0] |= 0x10;
378 cfg[0] |= 0x40; /* always set */
379 cfg[1] |= 0x80; /* enable WSS system */
380 cfg[1] &= ~0x40; /* disable IDE */
381 snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]);
382}
383
384static int __devinit sc6000_init_board(char __iomem *vport,
385 char __iomem *vmss_port, int dev)
339{ 386{
340 char answer[15]; 387 char answer[15];
341 char version[2]; 388 char version[2];
342 int mss_config = sc6000_irq_to_softcfg(irq) | 389 int mss_config = sc6000_irq_to_softcfg(irq[dev]) |
343 sc6000_dma_to_softcfg(dma); 390 sc6000_dma_to_softcfg(dma[dev]);
344 int config = mss_config | 391 int config = mss_config |
345 sc6000_mpu_irq_to_softcfg(mpu_irq); 392 sc6000_mpu_irq_to_softcfg(mpu_irq[dev]);
346 int err; 393 int err;
394 int cfg[2];
395 int old = 0;
347 396
348 err = sc6000_dsp_reset(vport); 397 err = sc6000_dsp_reset(vport);
349 if (err < 0) { 398 if (err < 0) {
@@ -360,7 +409,6 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
360 /* 409 /*
361 * My SC-6000 card return "SC-6000" in DSPCopyright, so 410 * My SC-6000 card return "SC-6000" in DSPCopyright, so
362 * if we have something different, we have to be warned. 411 * if we have something different, we have to be warned.
363 * Mine returns "SC-6000A " - KH
364 */ 412 */
365 if (strncmp("SC-6000", answer, 7)) 413 if (strncmp("SC-6000", answer, 7))
366 snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); 414 snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n");
@@ -372,13 +420,29 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
372 printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", 420 printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n",
373 answer, version[0], version[1]); 421 answer, version[0], version[1]);
374 422
375 /* 423 /* set configuration */
376 * 0x0A == (IRQ 7, DMA 1, MIRQ 0) 424 sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev],
377 */ 425 mss_port[dev]);
378 err = sc6000_cfg_write(vport, 0x0a); 426 if (sc6000_hw_cfg_write(vport, cfg) < 0) {
427 snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n");
428 return -EIO;
429 }
430 err = sc6000_setup_board(vport, config);
379 if (err < 0) { 431 if (err < 0) {
380 snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); 432 snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
381 return -EFAULT; 433 return -ENODEV;
434 }
435
436 sc6000_dsp_reset(vport);
437 sc6000_write(vport, COMMAND_5C);
438 if (sc6000_read(vport) < 0)
439 old = 1;
440 sc6000_dsp_reset(vport);
441
442 if (!old) {
443 sc6000_write(vport, COMMAND_60);
444 sc6000_write(vport, 0x02);
445 sc6000_dsp_reset(vport);
382 } 446 }
383 447
384 err = sc6000_setup_board(vport, config); 448 err = sc6000_setup_board(vport, config);
@@ -386,10 +450,9 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma,
386 snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); 450 snd_printk(KERN_ERR "sc6000_setup_board: failed!\n");
387 return -ENODEV; 451 return -ENODEV;
388 } 452 }
389
390 err = sc6000_init_mss(vport, config, vmss_port, mss_config); 453 err = sc6000_init_mss(vport, config, vmss_port, mss_config);
391 if (err < 0) { 454 if (err < 0) {
392 snd_printk(KERN_ERR "Can not initialize " 455 snd_printk(KERN_ERR "Cannot initialize "
393 "Microsoft Sound System mode.\n"); 456 "Microsoft Sound System mode.\n");
394 return -ENODEV; 457 return -ENODEV;
395 } 458 }
@@ -485,14 +548,16 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
485 struct snd_card *card; 548 struct snd_card *card;
486 struct snd_wss *chip; 549 struct snd_wss *chip;
487 struct snd_opl3 *opl3; 550 struct snd_opl3 *opl3;
488 char __iomem *vport; 551 char __iomem **vport;
489 char __iomem *vmss_port; 552 char __iomem *vmss_port;
490 553
491 554
492 err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); 555 err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport),
556 &card);
493 if (err < 0) 557 if (err < 0)
494 return err; 558 return err;
495 559
560 vport = card->private_data;
496 if (xirq == SNDRV_AUTO_IRQ) { 561 if (xirq == SNDRV_AUTO_IRQ) {
497 xirq = snd_legacy_find_free_irq(possible_irqs); 562 xirq = snd_legacy_find_free_irq(possible_irqs);
498 if (xirq < 0) { 563 if (xirq < 0) {
@@ -517,8 +582,8 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
517 err = -EBUSY; 582 err = -EBUSY;
518 goto err_exit; 583 goto err_exit;
519 } 584 }
520 vport = devm_ioport_map(devptr, port[dev], 0x10); 585 *vport = devm_ioport_map(devptr, port[dev], 0x10);
521 if (!vport) { 586 if (*vport == NULL) {
522 snd_printk(KERN_ERR PFX 587 snd_printk(KERN_ERR PFX
523 "I/O port cannot be iomaped.\n"); 588 "I/O port cannot be iomaped.\n");
524 err = -EBUSY; 589 err = -EBUSY;
@@ -533,7 +598,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
533 goto err_unmap1; 598 goto err_unmap1;
534 } 599 }
535 vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); 600 vmss_port = devm_ioport_map(devptr, mss_port[dev], 4);
536 if (!vport) { 601 if (!vmss_port) {
537 snd_printk(KERN_ERR PFX 602 snd_printk(KERN_ERR PFX
538 "MSS port I/O cannot be iomaped.\n"); 603 "MSS port I/O cannot be iomaped.\n");
539 err = -EBUSY; 604 err = -EBUSY;
@@ -544,7 +609,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
544 port[dev], xirq, xdma, 609 port[dev], xirq, xdma,
545 mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); 610 mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]);
546 611
547 err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); 612 err = sc6000_init_board(*vport, vmss_port, dev);
548 if (err < 0) 613 if (err < 0)
549 goto err_unmap2; 614 goto err_unmap2;
550 615
@@ -552,7 +617,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
552 WSS_HW_DETECT, 0, &chip); 617 WSS_HW_DETECT, 0, &chip);
553 if (err < 0) 618 if (err < 0)
554 goto err_unmap2; 619 goto err_unmap2;
555 card->private_data = chip;
556 620
557 err = snd_wss_pcm(chip, 0, NULL); 621 err = snd_wss_pcm(chip, 0, NULL);
558 if (err < 0) { 622 if (err < 0) {
@@ -608,6 +672,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
608 return 0; 672 return 0;
609 673
610err_unmap2: 674err_unmap2:
675 sc6000_setup_board(*vport, 0);
611 release_region(mss_port[dev], 4); 676 release_region(mss_port[dev], 4);
612err_unmap1: 677err_unmap1:
613 release_region(port[dev], 0x10); 678 release_region(port[dev], 0x10);
@@ -618,11 +683,17 @@ err_exit:
618 683
619static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) 684static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev)
620{ 685{
686 struct snd_card *card = dev_get_drvdata(devptr);
687 char __iomem **vport = card->private_data;
688
689 if (sc6000_setup_board(*vport, 0) < 0)
690 snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n");
691
621 release_region(port[dev], 0x10); 692 release_region(port[dev], 0x10);
622 release_region(mss_port[dev], 4); 693 release_region(mss_port[dev], 4);
623 694
624 snd_card_free(dev_get_drvdata(devptr));
625 dev_set_drvdata(devptr, NULL); 695 dev_set_drvdata(devptr, NULL);
696 snd_card_free(card);
626 return 0; 697 return 0;
627} 698}
628 699