1 /* 2 * Driver for Gallant SC-6000 soundcard. This card is also known as 3 * Audio Excel DSP 16 or Zoltrix AV302. 4 * These cards use CompuMedia ASC-9308 chip + AD1848 codec. 5 * 6 * Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl> 7 * 8 * I don't have documentation for this card. I used the driver 9 * for OSS/Free included in the kernel source as reference. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 */ 25 26 #include <linux/module.h> 27 #include <linux/delay.h> 28 #include <linux/isa.h> 29 #include <linux/io.h> 30 #include <asm/dma.h> 31 #include <sound/core.h> 32 #include <sound/wss.h> 33 #include <sound/opl3.h> 34 #include <sound/mpu401.h> 35 #include <sound/control.h> 36 #define SNDRV_LEGACY_FIND_FREE_IRQ 37 #define SNDRV_LEGACY_FIND_FREE_DMA 38 #include <sound/initval.h> 39 40 MODULE_AUTHOR("Krzysztof Helt"); 41 MODULE_DESCRIPTION("Gallant SC-6000"); 42 MODULE_LICENSE("GPL"); 43 MODULE_SUPPORTED_DEVICE("{{Gallant, SC-6000}," 44 "{AudioExcel, Audio Excel DSP 16}," 45 "{Zoltrix, AV302}}"); 46 47 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 48 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 49 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ 50 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220, 0x240 */ 51 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5, 7, 9, 10, 11 */ 52 static long mss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x530, 0xe80 */ 53 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 54 /* 0x300, 0x310, 0x320, 0x330 */ 55 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 */ 57 58 module_param_array(index, int, NULL, 0444); 59 MODULE_PARM_DESC(index, "Index value for sc-6000 based soundcard."); 60 module_param_array(id, charp, NULL, 0444); 61 MODULE_PARM_DESC(id, "ID string for sc-6000 based soundcard."); 62 module_param_array(enable, bool, NULL, 0444); 63 MODULE_PARM_DESC(enable, "Enable sc-6000 based soundcard."); 64 module_param_array(port, long, NULL, 0444); 65 MODULE_PARM_DESC(port, "Port # for sc-6000 driver."); 66 module_param_array(mss_port, long, NULL, 0444); 67 MODULE_PARM_DESC(mss_port, "MSS Port # for sc-6000 driver."); 68 module_param_array(mpu_port, long, NULL, 0444); 69 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for sc-6000 driver."); 70 module_param_array(irq, int, NULL, 0444); 71 MODULE_PARM_DESC(irq, "IRQ # for sc-6000 driver."); 72 module_param_array(mpu_irq, int, NULL, 0444); 73 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for sc-6000 driver."); 74 module_param_array(dma, int, NULL, 0444); 75 MODULE_PARM_DESC(dma, "DMA # for sc-6000 driver."); 76 77 /* 78 * Commands of SC6000's DSP (SBPRO+special). 79 * Some of them are COMMAND_xx, in the future they may change. 80 */ 81 #define WRITE_MDIRQ_CFG 0x50 /* Set M&I&DRQ mask (the real config) */ 82 #define COMMAND_52 0x52 /* */ 83 #define READ_HARD_CFG 0x58 /* Read Hardware Config (I/O base etc) */ 84 #define COMMAND_5C 0x5c /* */ 85 #define COMMAND_60 0x60 /* */ 86 #define COMMAND_66 0x66 /* */ 87 #define COMMAND_6C 0x6c /* */ 88 #define COMMAND_6E 0x6e /* */ 89 #define COMMAND_88 0x88 /* Unknown command */ 90 #define DSP_INIT_MSS 0x8c /* Enable Microsoft Sound System mode */ 91 #define COMMAND_C5 0xc5 /* */ 92 #define GET_DSP_VERSION 0xe1 /* Get DSP Version */ 93 #define GET_DSP_COPYRIGHT 0xe3 /* Get DSP Copyright */ 94 95 /* 96 * Offsets of SC6000 DSP I/O ports. The offset is added to base I/O port 97 * to have the actual I/O port. 98 * Register permissions are: 99 * (wo) == Write Only 100 * (ro) == Read Only 101 * (w-) == Write 102 * (r-) == Read 103 */ 104 #define DSP_RESET 0x06 /* offset of DSP RESET (wo) */ 105 #define DSP_READ 0x0a /* offset of DSP READ (ro) */ 106 #define DSP_WRITE 0x0c /* offset of DSP WRITE (w-) */ 107 #define DSP_COMMAND 0x0c /* offset of DSP COMMAND (w-) */ 108 #define DSP_STATUS 0x0c /* offset of DSP STATUS (r-) */ 109 #define DSP_DATAVAIL 0x0e /* offset of DSP DATA AVAILABLE (ro) */ 110 111 #define PFX "sc6000: " 112 #define DRV_NAME "SC-6000" 113 114 /* hardware dependent functions */ 115 116 /* 117 * sc6000_irq_to_softcfg - Decode irq number into cfg code. 118 */ 119 static __devinit unsigned char sc6000_irq_to_softcfg(int irq) 120 { 121 unsigned char val = 0; 122 123 switch (irq) { 124 case 5: 125 val = 0x28; 126 break; 127 case 7: 128 val = 0x8; 129 break; 130 case 9: 131 val = 0x10; 132 break; 133 case 10: 134 val = 0x18; 135 break; 136 case 11: 137 val = 0x20; 138 break; 139 default: 140 break; 141 } 142 return val; 143 } 144 145 /* 146 * sc6000_dma_to_softcfg - Decode dma number into cfg code. 147 */ 148 static __devinit unsigned char sc6000_dma_to_softcfg(int dma) 149 { 150 unsigned char val = 0; 151 152 switch (dma) { 153 case 0: 154 val = 1; 155 break; 156 case 1: 157 val = 2; 158 break; 159 case 3: 160 val = 3; 161 break; 162 default: 163 break; 164 } 165 return val; 166 } 167 168 /* 169 * sc6000_mpu_irq_to_softcfg - Decode MPU-401 irq number into cfg code. 170 */ 171 static __devinit unsigned char sc6000_mpu_irq_to_softcfg(int mpu_irq) 172 { 173 unsigned char val = 0; 174 175 switch (mpu_irq) { 176 case 5: 177 val = 4; 178 break; 179 case 7: 180 val = 0x44; 181 break; 182 case 9: 183 val = 0x84; 184 break; 185 case 10: 186 val = 0xc4; 187 break; 188 default: 189 break; 190 } 191 return val; 192 } 193 194 static __devinit int sc6000_wait_data(char __iomem *vport) 195 { 196 int loop = 1000; 197 unsigned char val = 0; 198 199 do { 200 val = ioread8(vport + DSP_DATAVAIL); 201 if (val & 0x80) 202 return 0; 203 cpu_relax(); 204 } while (loop--); 205 206 return -EAGAIN; 207 } 208 209 static __devinit int sc6000_read(char __iomem *vport) 210 { 211 if (sc6000_wait_data(vport)) 212 return -EBUSY; 213 214 return ioread8(vport + DSP_READ); 215 216 } 217 218 static __devinit int sc6000_write(char __iomem *vport, int cmd) 219 { 220 unsigned char val; 221 int loop = 500000; 222 223 do { 224 val = ioread8(vport + DSP_STATUS); 225 /* 226 * DSP ready to receive data if bit 7 of val == 0 227 */ 228 if (!(val & 0x80)) { 229 iowrite8(cmd, vport + DSP_COMMAND); 230 return 0; 231 } 232 cpu_relax(); 233 } while (loop--); 234 235 snd_printk(KERN_ERR "DSP Command (0x%x) timeout.\n", cmd); 236 237 return -EIO; 238 } 239 240 static int __devinit sc6000_dsp_get_answer(char __iomem *vport, int command, 241 char *data, int data_len) 242 { 243 int len = 0; 244 245 if (sc6000_write(vport, command)) { 246 snd_printk(KERN_ERR "CMD 0x%x: failed!\n", command); 247 return -EIO; 248 } 249 250 do { 251 int val = sc6000_read(vport); 252 253 if (val < 0) 254 break; 255 256 data[len++] = val; 257 258 } while (len < data_len); 259 260 /* 261 * If no more data available, return to the caller, no error if len>0. 262 * We have no other way to know when the string is finished. 263 */ 264 return len ? len : -EIO; 265 } 266 267 static int __devinit sc6000_dsp_reset(char __iomem *vport) 268 { 269 iowrite8(1, vport + DSP_RESET); 270 udelay(10); 271 iowrite8(0, vport + DSP_RESET); 272 udelay(20); 273 if (sc6000_read(vport) == 0xaa) 274 return 0; 275 return -ENODEV; 276 } 277 278 /* detection and initialization */ 279 static int __devinit sc6000_cfg_write(char __iomem *vport, 280 unsigned char softcfg) 281 { 282 283 if (sc6000_write(vport, WRITE_MDIRQ_CFG)) { 284 snd_printk(KERN_ERR "CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); 285 return -EIO; 286 } 287 if (sc6000_write(vport, softcfg)) { 288 snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); 289 return -EIO; 290 } 291 return 0; 292 } 293 294 static int __devinit sc6000_setup_board(char __iomem *vport, int config) 295 { 296 int loop = 10; 297 298 do { 299 if (sc6000_write(vport, COMMAND_88)) { 300 snd_printk(KERN_ERR "CMD 0x%x: failed!\n", 301 COMMAND_88); 302 return -EIO; 303 } 304 } while ((sc6000_wait_data(vport) < 0) && loop--); 305 306 if (sc6000_read(vport) < 0) { 307 snd_printk(KERN_ERR "sc6000_read after CMD 0x%x: failed\n", 308 COMMAND_88); 309 return -EIO; 310 } 311 312 if (sc6000_cfg_write(vport, config)) 313 return -ENODEV; 314 315 return 0; 316 } 317 318 static int __devinit sc6000_init_mss(char __iomem *vport, int config, 319 char __iomem *vmss_port, int mss_config) 320 { 321 if (sc6000_write(vport, DSP_INIT_MSS)) { 322 snd_printk(KERN_ERR "sc6000_init_mss [0x%x]: failed!\n", 323 DSP_INIT_MSS); 324 return -EIO; 325 } 326 327 msleep(10); 328 329 if (sc6000_cfg_write(vport, config)) 330 return -EIO; 331 332 iowrite8(mss_config, vmss_port); 333 334 return 0; 335 } 336 337 static int __devinit sc6000_init_board(char __iomem *vport, int irq, int dma, 338 char __iomem *vmss_port, int mpu_irq) 339 { 340 char answer[15]; 341 char version[2]; 342 int mss_config = sc6000_irq_to_softcfg(irq) | 343 sc6000_dma_to_softcfg(dma); 344 int config = mss_config | 345 sc6000_mpu_irq_to_softcfg(mpu_irq); 346 int err; 347 348 err = sc6000_dsp_reset(vport); 349 if (err < 0) { 350 snd_printk(KERN_ERR "sc6000_dsp_reset: failed!\n"); 351 return err; 352 } 353 354 memset(answer, 0, sizeof(answer)); 355 err = sc6000_dsp_get_answer(vport, GET_DSP_COPYRIGHT, answer, 15); 356 if (err <= 0) { 357 snd_printk(KERN_ERR "sc6000_dsp_copyright: failed!\n"); 358 return -ENODEV; 359 } 360 /* 361 * My SC-6000 card return "SC-6000" in DSPCopyright, so 362 * if we have something different, we have to be warned. 363 * Mine returns "SC-6000A " - KH 364 */ 365 if (strncmp("SC-6000", answer, 7)) 366 snd_printk(KERN_WARNING "Warning: non SC-6000 audio card!\n"); 367 368 if (sc6000_dsp_get_answer(vport, GET_DSP_VERSION, version, 2) < 2) { 369 snd_printk(KERN_ERR "sc6000_dsp_version: failed!\n"); 370 return -ENODEV; 371 } 372 printk(KERN_INFO PFX "Detected model: %s, DSP version %d.%d\n", 373 answer, version[0], version[1]); 374 375 /* 376 * 0x0A == (IRQ 7, DMA 1, MIRQ 0) 377 */ 378 err = sc6000_cfg_write(vport, 0x0a); 379 if (err < 0) { 380 snd_printk(KERN_ERR "sc6000_cfg_write: failed!\n"); 381 return -EFAULT; 382 } 383 384 err = sc6000_setup_board(vport, config); 385 if (err < 0) { 386 snd_printk(KERN_ERR "sc6000_setup_board: failed!\n"); 387 return -ENODEV; 388 } 389 390 err = sc6000_init_mss(vport, config, vmss_port, mss_config); 391 if (err < 0) { 392 snd_printk(KERN_ERR "Can not initialize " 393 "Microsoft Sound System mode.\n"); 394 return -ENODEV; 395 } 396 397 return 0; 398 } 399 400 static int __devinit snd_sc6000_mixer(struct snd_wss *chip) 401 { 402 struct snd_card *card = chip->card; 403 struct snd_ctl_elem_id id1, id2; 404 int err; 405 406 memset(&id1, 0, sizeof(id1)); 407 memset(&id2, 0, sizeof(id2)); 408 id1.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 409 id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 410 /* reassign AUX0 to FM */ 411 strcpy(id1.name, "Aux Playback Switch"); 412 strcpy(id2.name, "FM Playback Switch"); 413 err = snd_ctl_rename_id(card, &id1, &id2); 414 if (err < 0) 415 return err; 416 strcpy(id1.name, "Aux Playback Volume"); 417 strcpy(id2.name, "FM Playback Volume"); 418 err = snd_ctl_rename_id(card, &id1, &id2); 419 if (err < 0) 420 return err; 421 /* reassign AUX1 to CD */ 422 strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; 423 strcpy(id2.name, "CD Playback Switch"); 424 err = snd_ctl_rename_id(card, &id1, &id2); 425 if (err < 0) 426 return err; 427 strcpy(id1.name, "Aux Playback Volume"); 428 strcpy(id2.name, "CD Playback Volume"); 429 err = snd_ctl_rename_id(card, &id1, &id2); 430 if (err < 0) 431 return err; 432 return 0; 433 } 434 435 static int __devinit snd_sc6000_match(struct device *devptr, unsigned int dev) 436 { 437 if (!enable[dev]) 438 return 0; 439 if (port[dev] == SNDRV_AUTO_PORT) { 440 printk(KERN_ERR PFX "specify IO port\n"); 441 return 0; 442 } 443 if (mss_port[dev] == SNDRV_AUTO_PORT) { 444 printk(KERN_ERR PFX "specify MSS port\n"); 445 return 0; 446 } 447 if (port[dev] != 0x220 && port[dev] != 0x240) { 448 printk(KERN_ERR PFX "Port must be 0x220 or 0x240\n"); 449 return 0; 450 } 451 if (mss_port[dev] != 0x530 && mss_port[dev] != 0xe80) { 452 printk(KERN_ERR PFX "MSS port must be 0x530 or 0xe80\n"); 453 return 0; 454 } 455 if (irq[dev] != SNDRV_AUTO_IRQ && !sc6000_irq_to_softcfg(irq[dev])) { 456 printk(KERN_ERR PFX "invalid IRQ %d\n", irq[dev]); 457 return 0; 458 } 459 if (dma[dev] != SNDRV_AUTO_DMA && !sc6000_dma_to_softcfg(dma[dev])) { 460 printk(KERN_ERR PFX "invalid DMA %d\n", dma[dev]); 461 return 0; 462 } 463 if (mpu_port[dev] != SNDRV_AUTO_PORT && 464 (mpu_port[dev] & ~0x30L) != 0x300) { 465 printk(KERN_ERR PFX "invalid MPU-401 port %lx\n", 466 mpu_port[dev]); 467 return 0; 468 } 469 if (mpu_port[dev] != SNDRV_AUTO_PORT && 470 mpu_irq[dev] != SNDRV_AUTO_IRQ && mpu_irq[dev] != 0 && 471 !sc6000_mpu_irq_to_softcfg(mpu_irq[dev])) { 472 printk(KERN_ERR PFX "invalid MPU-401 IRQ %d\n", mpu_irq[dev]); 473 return 0; 474 } 475 return 1; 476 } 477 478 static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev) 479 { 480 static int possible_irqs[] = { 5, 7, 9, 10, 11, -1 }; 481 static int possible_dmas[] = { 1, 3, 0, -1 }; 482 int err; 483 int xirq = irq[dev]; 484 int xdma = dma[dev]; 485 struct snd_card *card; 486 struct snd_wss *chip; 487 struct snd_opl3 *opl3; 488 char __iomem *vport; 489 char __iomem *vmss_port; 490 491 492 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); 493 if (!card) 494 return -ENOMEM; 495 496 if (xirq == SNDRV_AUTO_IRQ) { 497 xirq = snd_legacy_find_free_irq(possible_irqs); 498 if (xirq < 0) { 499 snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); 500 err = -EBUSY; 501 goto err_exit; 502 } 503 } 504 505 if (xdma == SNDRV_AUTO_DMA) { 506 xdma = snd_legacy_find_free_dma(possible_dmas); 507 if (xdma < 0) { 508 snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); 509 err = -EBUSY; 510 goto err_exit; 511 } 512 } 513 514 if (!request_region(port[dev], 0x10, DRV_NAME)) { 515 snd_printk(KERN_ERR PFX 516 "I/O port region is already in use.\n"); 517 err = -EBUSY; 518 goto err_exit; 519 } 520 vport = devm_ioport_map(devptr, port[dev], 0x10); 521 if (!vport) { 522 snd_printk(KERN_ERR PFX 523 "I/O port cannot be iomaped.\n"); 524 err = -EBUSY; 525 goto err_unmap1; 526 } 527 528 /* to make it marked as used */ 529 if (!request_region(mss_port[dev], 4, DRV_NAME)) { 530 snd_printk(KERN_ERR PFX 531 "SC-6000 port I/O port region is already in use.\n"); 532 err = -EBUSY; 533 goto err_unmap1; 534 } 535 vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); 536 if (!vport) { 537 snd_printk(KERN_ERR PFX 538 "MSS port I/O cannot be iomaped.\n"); 539 err = -EBUSY; 540 goto err_unmap2; 541 } 542 543 snd_printd("Initializing BASE[0x%lx] IRQ[%d] DMA[%d] MIRQ[%d]\n", 544 port[dev], xirq, xdma, 545 mpu_irq[dev] == SNDRV_AUTO_IRQ ? 0 : mpu_irq[dev]); 546 547 err = sc6000_init_board(vport, xirq, xdma, vmss_port, mpu_irq[dev]); 548 if (err < 0) 549 goto err_unmap2; 550 551 err = snd_wss_create(card, mss_port[dev] + 4, -1, xirq, xdma, -1, 552 WSS_HW_DETECT, 0, &chip); 553 if (err < 0) 554 goto err_unmap2; 555 card->private_data = chip; 556 557 err = snd_wss_pcm(chip, 0, NULL); 558 if (err < 0) { 559 snd_printk(KERN_ERR PFX 560 "error creating new WSS PCM device\n"); 561 goto err_unmap2; 562 } 563 err = snd_wss_mixer(chip); 564 if (err < 0) { 565 snd_printk(KERN_ERR PFX "error creating new WSS mixer\n"); 566 goto err_unmap2; 567 } 568 err = snd_sc6000_mixer(chip); 569 if (err < 0) { 570 snd_printk(KERN_ERR PFX "the mixer rewrite failed\n"); 571 goto err_unmap2; 572 } 573 if (snd_opl3_create(card, 574 0x388, 0x388 + 2, 575 OPL3_HW_AUTO, 0, &opl3) < 0) { 576 snd_printk(KERN_ERR PFX "no OPL device at 0x%x-0x%x ?\n", 577 0x388, 0x388 + 2); 578 } else { 579 err = snd_opl3_timer_new(opl3, 0, 1); 580 if (err < 0) 581 goto err_unmap2; 582 583 err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); 584 if (err < 0) 585 goto err_unmap2; 586 } 587 588 if (mpu_port[dev] != SNDRV_AUTO_PORT) { 589 if (mpu_irq[dev] == SNDRV_AUTO_IRQ) 590 mpu_irq[dev] = -1; 591 if (snd_mpu401_uart_new(card, 0, 592 MPU401_HW_MPU401, 593 mpu_port[dev], 0, 594 mpu_irq[dev], IRQF_DISABLED, 595 NULL) < 0) 596 snd_printk(KERN_ERR "no MPU-401 device at 0x%lx ?\n", 597 mpu_port[dev]); 598 } 599 600 strcpy(card->driver, DRV_NAME); 601 strcpy(card->shortname, "SC-6000"); 602 sprintf(card->longname, "Gallant SC-6000 at 0x%lx, irq %d, dma %d", 603 mss_port[dev], xirq, xdma); 604 605 snd_card_set_dev(card, devptr); 606 607 err = snd_card_register(card); 608 if (err < 0) 609 goto err_unmap2; 610 611 dev_set_drvdata(devptr, card); 612 return 0; 613 614 err_unmap2: 615 release_region(mss_port[dev], 4); 616 err_unmap1: 617 release_region(port[dev], 0x10); 618 err_exit: 619 snd_card_free(card); 620 return err; 621 } 622 623 static int __devexit snd_sc6000_remove(struct device *devptr, unsigned int dev) 624 { 625 release_region(port[dev], 0x10); 626 release_region(mss_port[dev], 4); 627 628 snd_card_free(dev_get_drvdata(devptr)); 629 dev_set_drvdata(devptr, NULL); 630 return 0; 631 } 632 633 static struct isa_driver snd_sc6000_driver = { 634 .match = snd_sc6000_match, 635 .probe = snd_sc6000_probe, 636 .remove = __devexit_p(snd_sc6000_remove), 637 /* FIXME: suspend/resume */ 638 .driver = { 639 .name = DRV_NAME, 640 }, 641 }; 642 643 644 static int __init alsa_card_sc6000_init(void) 645 { 646 return isa_register_driver(&snd_sc6000_driver, SNDRV_CARDS); 647 } 648 649 static void __exit alsa_card_sc6000_exit(void) 650 { 651 isa_unregister_driver(&snd_sc6000_driver); 652 } 653 654 module_init(alsa_card_sc6000_init) 655 module_exit(alsa_card_sc6000_exit) 656