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