diff options
-rw-r--r-- | Documentation/sound/alsa/ALSA-Configuration.txt | 4 | ||||
-rw-r--r-- | sound/isa/Kconfig | 7 | ||||
-rw-r--r-- | sound/isa/sc6000.c | 134 |
3 files changed, 114 insertions, 31 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 096af12a0afa..5c08d96f407c 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
@@ -1570,13 +1570,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
1570 | Module snd-sc6000 | 1570 | Module snd-sc6000 |
1571 | ----------------- | 1571 | ----------------- |
1572 | 1572 | ||
1573 | Module for Gallant SC-6000 soundcard. | 1573 | Module for Gallant SC-6000 soundcard and later models: SC-6600 |
1574 | and SC-7000. | ||
1574 | 1575 | ||
1575 | port - Port # (0x220 or 0x240) | 1576 | port - Port # (0x220 or 0x240) |
1576 | mss_port - MSS Port # (0x530 or 0xe80) | 1577 | mss_port - MSS Port # (0x530 or 0xe80) |
1577 | irq - IRQ # (5,7,9,10,11) | 1578 | irq - IRQ # (5,7,9,10,11) |
1578 | mpu_irq - MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq | 1579 | mpu_irq - MPU-401 IRQ # (5,7,9,10) ,0 - no MPU-401 irq |
1579 | dma - DMA # (1,3,0) | 1580 | dma - DMA # (1,3,0) |
1581 | joystick - Enable gameport - 0 = disable (default), 1 = enable | ||
1580 | 1582 | ||
1581 | This module supports multiple cards. | 1583 | This module supports multiple cards. |
1582 | 1584 | ||
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index c6942a4de99b..51a7e3777e17 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
@@ -177,15 +177,18 @@ config SND_ES18XX | |||
177 | will be called snd-es18xx. | 177 | will be called snd-es18xx. |
178 | 178 | ||
179 | config SND_SC6000 | 179 | config SND_SC6000 |
180 | tristate "Gallant SC-6000, Audio Excel DSP 16" | 180 | tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16" |
181 | depends on HAS_IOPORT | 181 | depends on HAS_IOPORT |
182 | select SND_WSS_LIB | 182 | select SND_WSS_LIB |
183 | select SND_OPL3_LIB | 183 | select SND_OPL3_LIB |
184 | select SND_MPU401_UART | 184 | select SND_MPU401_UART |
185 | help | 185 | help |
186 | Say Y here to include support for Gallant SC-6000 card and clones: | 186 | Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000 |
187 | cards and clones: | ||
187 | Audio Excel DSP 16 and Zoltrix AV302. | 188 | Audio Excel DSP 16 and Zoltrix AV302. |
188 | 189 | ||
190 | These cards are based on CompuMedia ASC-9308 or ASC-9408 chips. | ||
191 | |||
189 | To compile this driver as a module, choose M here: the module | 192 | To compile this driver as a module, choose M here: the module |
190 | will be called snd-sc6000. | 193 | will be called snd-sc6000. |
191 | 194 | ||
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 782010608ef4..9a8bbf6dd62a 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 | * |
@@ -54,6 +56,7 @@ static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | |||
54 | /* 0x300, 0x310, 0x320, 0x330 */ | 56 | /* 0x300, 0x310, 0x320, 0x330 */ |
55 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */ | 57 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 0 */ |
56 | static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */ | 58 | static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0, 1, 3 */ |
59 | static bool joystick[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = false }; | ||
57 | 60 | ||
58 | module_param_array(index, int, NULL, 0444); | 61 | module_param_array(index, int, NULL, 0444); |
59 | MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); | 62 | MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); |
@@ -73,6 +76,8 @@ module_param_array(mpu_irq, int, NULL, 0444); | |||
73 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); | 76 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); |
74 | module_param_array(dma, int, NULL, 0444); | 77 | module_param_array(dma, int, NULL, 0444); |
75 | MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); | 78 | MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); |
79 | module_param_array(joystick, bool, NULL, 0444); | ||
80 | MODULE_PARM_DESC(joystick, "Enable gameport."); | ||
76 | 81 | ||
77 | /* | 82 | /* |
78 | * Commands of SC6000's DSP (SBPRO+special). | 83 | * Commands of SC6000's DSP (SBPRO+special). |
@@ -191,7 +196,7 @@ static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) | |||
191 | return val; | 196 | return val; |
192 | } | 197 | } |
193 | 198 | ||
194 | static __devinit int sc6000_wait_data(char __iomem *vport) | 199 | static int sc6000_wait_data(char __iomem *vport) |
195 | { | 200 | { |
196 | int loop = 1000; | 201 | int loop = 1000; |
197 | unsigned char val = 0; | 202 | unsigned char val = 0; |
@@ -206,7 +211,7 @@ static __devinit int sc6000_wait_data(char __iomem *vport) | |||
206 | return -EAGAIN; | 211 | return -EAGAIN; |
207 | } | 212 | } |
208 | 213 | ||
209 | static __devinit int sc6000_read(char __iomem *vport) | 214 | static int sc6000_read(char __iomem *vport) |
210 | { | 215 | { |
211 | if (sc6000_wait_data(vport)) | 216 | if (sc6000_wait_data(vport)) |
212 | return -EBUSY; | 217 | return -EBUSY; |
@@ -215,7 +220,7 @@ static __devinit int sc6000_read(char __iomem *vport) | |||
215 | 220 | ||
216 | } | 221 | } |
217 | 222 | ||
218 | static __devinit int sc6000_write(char __iomem *vport, int cmd) | 223 | static int sc6000_write(char __iomem *vport, int cmd) |
219 | { | 224 | { |
220 | unsigned char val; | 225 | unsigned char val; |
221 | int loop = 500000; | 226 | int loop = 500000; |
@@ -276,8 +281,33 @@ static int __devinit sc6000_dsp_reset(char __iomem *vport) | |||
276 | } | 281 | } |
277 | 282 | ||
278 | /* detection and initialization */ | 283 | /* detection and initialization */ |
279 | static int __devinit sc6000_cfg_write(char __iomem *vport, | 284 | static int __devinit sc6000_hw_cfg_write(char __iomem *vport, const int *cfg) |
280 | unsigned char softcfg) | 285 | { |
286 | if (sc6000_write(vport, COMMAND_6C) < 0) { | ||
287 | snd_printk(KERN_WARNING "CMD 0x%x: failed!\n", COMMAND_6C); | ||
288 | return -EIO; | ||
289 | } | ||
290 | if (sc6000_write(vport, COMMAND_5C) < 0) { | ||
291 | snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_5C); | ||
292 | return -EIO; | ||
293 | } | ||
294 | if (sc6000_write(vport, cfg[0]) < 0) { | ||
295 | snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[0]); | ||
296 | return -EIO; | ||
297 | } | ||
298 | if (sc6000_write(vport, cfg[1]) < 0) { | ||
299 | snd_printk(KERN_ERR "DATA 0x%x: failed!\n", cfg[1]); | ||
300 | return -EIO; | ||
301 | } | ||
302 | if (sc6000_write(vport, COMMAND_C5) < 0) { | ||
303 | snd_printk(KERN_ERR "CMD 0x%x: failed!\n", COMMAND_C5); | ||
304 | return -EIO; | ||
305 | } | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int sc6000_cfg_write(char __iomem *vport, unsigned char softcfg) | ||
281 | { | 311 | { |
282 | 312 | ||
283 | if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { | 313 | if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { |
@@ -291,7 +321,7 @@ static int __devinit sc6000_cfg_write(char __iomem *vport, | |||
291 | return 0; | 321 | return 0; |
292 | } | 322 | } |
293 | 323 | ||
294 | static int __devinit sc6000_setup_board(char __iomem *vport, int config) | 324 | static int sc6000_setup_board(char __iomem *vport, int config) |
295 | { | 325 | { |
296 | int loop = 10; | 326 | int loop = 10; |
297 | 327 | ||
@@ -334,16 +364,39 @@ static int __devinit sc6000_init_mss(char __iomem *vport, int config, | |||
334 | return 0; | 364 | return 0; |
335 | } | 365 | } |
336 | 366 | ||
337 | static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, | 367 | static void __devinit sc6000_hw_cfg_encode(char __iomem *vport, int *cfg, |
338 | char __iomem *vmss_port, int mpu_irq) | 368 | long xport, long xmpu, |
369 | long xmss_port, int joystick) | ||
370 | { | ||
371 | cfg[0] = 0; | ||
372 | cfg[1] = 0; | ||
373 | if (xport == 0x240) | ||
374 | cfg[0] |= 1; | ||
375 | if (xmpu != SNDRV_AUTO_PORT) { | ||
376 | cfg[0] |= (xmpu & 0x30) >> 2; | ||
377 | cfg[1] |= 0x20; | ||
378 | } | ||
379 | if (xmss_port == 0xe80) | ||
380 | cfg[0] |= 0x10; | ||
381 | cfg[0] |= 0x40; /* always set */ | ||
382 | if (!joystick) | ||
383 | cfg[0] |= 0x02; | ||
384 | cfg[1] |= 0x80; /* enable WSS system */ | ||
385 | cfg[1] &= ~0x40; /* disable IDE */ | ||
386 | snd_printd("hw cfg %x, %x\n", cfg[0], cfg[1]); | ||
387 | } | ||
388 | |||
389 | static int __devinit sc6000_init_board(char __iomem *vport, | ||
390 | char __iomem *vmss_port, int dev) | ||
339 | { | 391 | { |
340 | char answer[15]; | 392 | char answer[15]; |
341 | char version[2]; | 393 | char version[2]; |
342 | int mss_config = sc6000_irq_to_softcfg(irq) | | 394 | int mss_config = sc6000_irq_to_softcfg(irq[dev]) | |
343 | sc6000_dma_to_softcfg(dma); | 395 | sc6000_dma_to_softcfg(dma[dev]); |
344 | int config = mss_config | | 396 | int config = mss_config | |
345 | sc6000_mpu_irq_to_softcfg(mpu_irq); | 397 | sc6000_mpu_irq_to_softcfg(mpu_irq[dev]); |
346 | int err; | 398 | int err; |
399 | int old = 0; | ||
347 | 400 | ||
348 | err = sc6000_dsp_reset(vport); | 401 | err = sc6000_dsp_reset(vport); |
349 | if (err < 0) { | 402 | if (err < 0) { |
@@ -360,7 +413,6 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, | |||
360 | /* | 413 | /* |
361 | * My SC-6000 card return "SC-6000" in DSPCopyright, so | 414 | * My SC-6000 card return "SC-6000" in DSPCopyright, so |
362 | * if we have something different, we have to be warned. | 415 | * if we have something different, we have to be warned. |
363 | * Mine returns "SC-6000A " - KH | ||
364 | */ | 416 | */ |
365 | if (strncmp("SC-6000", answer, 7)) | 417 | if (strncmp("SC-6000", answer, 7)) |
366 | snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); | 418 | snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); |
@@ -372,13 +424,32 @@ 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", | 424 | printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", |
373 | answer, version[0], version[1]); | 425 | answer, version[0], version[1]); |
374 | 426 | ||
375 | /* | 427 | /* set configuration */ |
376 | * 0x0A == (IRQ 7, DMA 1, MIRQ 0) | 428 | sc6000_write(vport, COMMAND_5C); |
377 | */ | 429 | if (sc6000_read(vport) < 0) |
378 | err = sc6000_cfg_write(vport, 0x0a); | 430 | old = 1; |
431 | |||
432 | if (!old) { | ||
433 | int cfg[2]; | ||
434 | sc6000_hw_cfg_encode(vport, &cfg[0], port[dev], mpu_port[dev], | ||
435 | mss_port[dev], joystick[dev]); | ||
436 | if (sc6000_hw_cfg_write(vport, cfg) < 0) { | ||
437 | snd_printk(KERN_ERR "sc6000_hw_cfg_write: failed!\n"); | ||
438 | return -EIO; | ||
439 | } | ||
440 | } | ||
441 | err = sc6000_setup_board(vport, config); | ||
379 | if (err < 0) { | 442 | if (err < 0) { |
380 | snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); | 443 | snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); |
381 | return -EFAULT; | 444 | return -ENODEV; |
445 | } | ||
446 | |||
447 | sc6000_dsp_reset(vport); | ||
448 | |||
449 | if (!old) { | ||
450 | sc6000_write(vport, COMMAND_60); | ||
451 | sc6000_write(vport, 0x02); | ||
452 | sc6000_dsp_reset(vport); | ||
382 | } | 453 | } |
383 | 454 | ||
384 | err = sc6000_setup_board(vport, config); | 455 | err = sc6000_setup_board(vport, config); |
@@ -386,10 +457,9 @@ static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, | |||
386 | snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); | 457 | snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); |
387 | return -ENODEV; | 458 | return -ENODEV; |
388 | } | 459 | } |
389 | |||
390 | err = sc6000_init_mss(vport, config, vmss_port, mss_config); | 460 | err = sc6000_init_mss(vport, config, vmss_port, mss_config); |
391 | if (err < 0) { | 461 | if (err < 0) { |
392 | snd_printk(KERN_ERR "Can not initialize " | 462 | snd_printk(KERN_ERR "Cannot initialize " |
393 | "Microsoft Sound System mode.\n"); | 463 | "Microsoft Sound System mode.\n"); |
394 | return -ENODEV; | 464 | return -ENODEV; |
395 | } | 465 | } |
@@ -485,14 +555,16 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
485 | struct snd_card *card; | 555 | struct snd_card *card; |
486 | struct snd_wss *chip; | 556 | struct snd_wss *chip; |
487 | struct snd_opl3 *opl3; | 557 | struct snd_opl3 *opl3; |
488 | char __iomem *vport; | 558 | char __iomem **vport; |
489 | char __iomem *vmss_port; | 559 | char __iomem *vmss_port; |
490 | 560 | ||
491 | 561 | ||
492 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | 562 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, sizeof(vport), |
563 | &card); | ||
493 | if (err < 0) | 564 | if (err < 0) |
494 | return err; | 565 | return err; |
495 | 566 | ||
567 | vport = card->private_data; | ||
496 | if (xirq == SNDRV_AUTO_IRQ) { | 568 | if (xirq == SNDRV_AUTO_IRQ) { |
497 | xirq = snd_legacy_find_free_irq(possible_irqs); | 569 | xirq = snd_legacy_find_free_irq(possible_irqs); |
498 | if (xirq < 0) { | 570 | if (xirq < 0) { |
@@ -517,8 +589,8 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
517 | err = -EBUSY; | 589 | err = -EBUSY; |
518 | goto err_exit; | 590 | goto err_exit; |
519 | } | 591 | } |
520 | vport = devm_ioport_map(devptr, port[dev], 0x10); | 592 | *vport = devm_ioport_map(devptr, port[dev], 0x10); |
521 | if (!vport) { | 593 | if (*vport == NULL) { |
522 | snd_printk(KERN_ERR PFX | 594 | snd_printk(KERN_ERR PFX |
523 | "I/O port cannot be iomaped.\n"); | 595 | "I/O port cannot be iomaped.\n"); |
524 | err = -EBUSY; | 596 | err = -EBUSY; |
@@ -533,7 +605,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
533 | goto err_unmap1; | 605 | goto err_unmap1; |
534 | } | 606 | } |
535 | vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); | 607 | vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); |
536 | if (!vport) { | 608 | if (!vmss_port) { |
537 | snd_printk(KERN_ERR PFX | 609 | snd_printk(KERN_ERR PFX |
538 | "MSS port I/O cannot be iomaped.\n"); | 610 | "MSS port I/O cannot be iomaped.\n"); |
539 | err = -EBUSY; | 611 | err = -EBUSY; |
@@ -544,7 +616,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
544 | port[dev], xirq, xdma, | 616 | port[dev], xirq, xdma, |
545 | mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); | 617 | mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); |
546 | 618 | ||
547 | err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); | 619 | err = sc6000_init_board(*vport, vmss_port, dev); |
548 | if (err < 0) | 620 | if (err < 0) |
549 | goto err_unmap2; | 621 | goto err_unmap2; |
550 | 622 | ||
@@ -552,7 +624,6 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
552 | WSS_HW_DETECT, 0, &chip); | 624 | WSS_HW_DETECT, 0, &chip); |
553 | if (err < 0) | 625 | if (err < 0) |
554 | goto err_unmap2; | 626 | goto err_unmap2; |
555 | card->private_data = chip; | ||
556 | 627 | ||
557 | err = snd_wss_pcm(chip, 0, NULL); | 628 | err = snd_wss_pcm(chip, 0, NULL); |
558 | if (err < 0) { | 629 | if (err < 0) { |
@@ -608,6 +679,7 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
608 | return 0; | 679 | return 0; |
609 | 680 | ||
610 | err_unmap2: | 681 | err_unmap2: |
682 | sc6000_setup_board(*vport, 0); | ||
611 | release_region(mss_port[dev], 4); | 683 | release_region(mss_port[dev], 4); |
612 | err_unmap1: | 684 | err_unmap1: |
613 | release_region(port[dev], 0x10); | 685 | release_region(port[dev], 0x10); |
@@ -618,11 +690,17 @@ err_exit: | |||
618 | 690 | ||
619 | static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) | 691 | static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) |
620 | { | 692 | { |
693 | struct snd_card *card = dev_get_drvdata(devptr); | ||
694 | char __iomem **vport = card->private_data; | ||
695 | |||
696 | if (sc6000_setup_board(*vport, 0) < 0) | ||
697 | snd_printk(KERN_WARNING "sc6000_setup_board failed on exit!\n"); | ||
698 | |||
621 | release_region(port[dev], 0x10); | 699 | release_region(port[dev], 0x10); |
622 | release_region(mss_port[dev], 4); | 700 | release_region(mss_port[dev], 4); |
623 | 701 | ||
624 | snd_card_free(dev_get_drvdata(devptr)); | ||
625 | dev_set_drvdata(devptr, NULL); | 702 | dev_set_drvdata(devptr, NULL); |
703 | snd_card_free(card); | ||
626 | return 0; | 704 | return 0; |
627 | } | 705 | } |
628 | 706 | ||