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