1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Aztech AZT1605/AZT2316 Driver 4 * Copyright (C) 2007,2010 Rene Herman 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/module.h> 9 #include <linux/isa.h> 10 #include <linux/delay.h> 11 #include <linux/io.h> 12 #include <asm/processor.h> 13 #include <sound/core.h> 14 #include <sound/initval.h> 15 #include <sound/wss.h> 16 #include <sound/mpu401.h> 17 #include <sound/opl3.h> 18 19 MODULE_DESCRIPTION(CRD_NAME); 20 MODULE_AUTHOR("Rene Herman"); 21 MODULE_LICENSE("GPL"); 22 23 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 24 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 25 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; 26 27 module_param_array(index, int, NULL, 0444); 28 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard."); 29 module_param_array(id, charp, NULL, 0444); 30 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard."); 31 module_param_array(enable, bool, NULL, 0444); 32 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard."); 33 34 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 35 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 36 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 37 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 38 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 39 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; 40 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; 41 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; 42 43 module_param_hw_array(port, long, ioport, NULL, 0444); 44 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver."); 45 module_param_hw_array(wss_port, long, ioport, NULL, 0444); 46 MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver."); 47 module_param_hw_array(mpu_port, long, ioport, NULL, 0444); 48 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver."); 49 module_param_hw_array(fm_port, long, ioport, NULL, 0444); 50 MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver."); 51 module_param_hw_array(irq, int, irq, NULL, 0444); 52 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver."); 53 module_param_hw_array(mpu_irq, int, irq, NULL, 0444); 54 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver."); 55 module_param_hw_array(dma1, int, dma, NULL, 0444); 56 MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver."); 57 module_param_hw_array(dma2, int, dma, NULL, 0444); 58 MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver."); 59 60 /* 61 * Generic SB DSP support routines 62 */ 63 64 #define DSP_PORT_RESET 0x6 65 #define DSP_PORT_READ 0xa 66 #define DSP_PORT_COMMAND 0xc 67 #define DSP_PORT_STATUS 0xc 68 #define DSP_PORT_DATA_AVAIL 0xe 69 70 #define DSP_SIGNATURE 0xaa 71 72 #define DSP_COMMAND_GET_VERSION 0xe1 73 74 static int dsp_get_byte(void __iomem *port, u8 *val) 75 { 76 int loops = 1000; 77 78 while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) { 79 if (!loops--) 80 return -EIO; 81 cpu_relax(); 82 } 83 *val = ioread8(port + DSP_PORT_READ); 84 return 0; 85 } 86 87 static int dsp_reset(void __iomem *port) 88 { 89 u8 val; 90 91 iowrite8(1, port + DSP_PORT_RESET); 92 udelay(10); 93 iowrite8(0, port + DSP_PORT_RESET); 94 95 if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE) 96 return -ENODEV; 97 98 return 0; 99 } 100 101 static int dsp_command(void __iomem *port, u8 cmd) 102 { 103 int loops = 1000; 104 105 while (ioread8(port + DSP_PORT_STATUS) & 0x80) { 106 if (!loops--) 107 return -EIO; 108 cpu_relax(); 109 } 110 iowrite8(cmd, port + DSP_PORT_COMMAND); 111 return 0; 112 } 113 114 static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor) 115 { 116 int err; 117 118 err = dsp_command(port, DSP_COMMAND_GET_VERSION); 119 if (err < 0) 120 return err; 121 122 err = dsp_get_byte(port, major); 123 if (err < 0) 124 return err; 125 126 err = dsp_get_byte(port, minor); 127 if (err < 0) 128 return err; 129 130 return 0; 131 } 132 133 /* 134 * Generic WSS support routines 135 */ 136 137 #define WSS_CONFIG_DMA_0 (1 << 0) 138 #define WSS_CONFIG_DMA_1 (2 << 0) 139 #define WSS_CONFIG_DMA_3 (3 << 0) 140 #define WSS_CONFIG_DUPLEX (1 << 2) 141 #define WSS_CONFIG_IRQ_7 (1 << 3) 142 #define WSS_CONFIG_IRQ_9 (2 << 3) 143 #define WSS_CONFIG_IRQ_10 (3 << 3) 144 #define WSS_CONFIG_IRQ_11 (4 << 3) 145 146 #define WSS_PORT_CONFIG 0 147 #define WSS_PORT_SIGNATURE 3 148 149 #define WSS_SIGNATURE 4 150 151 static int wss_detect(void __iomem *wss_port) 152 { 153 if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE) 154 return -ENODEV; 155 156 return 0; 157 } 158 159 static void wss_set_config(void __iomem *wss_port, u8 wss_config) 160 { 161 iowrite8(wss_config, wss_port + WSS_PORT_CONFIG); 162 } 163 164 /* 165 * Aztech Sound Galaxy specifics 166 */ 167 168 #define GALAXY_PORT_CONFIG 1024 169 #define CONFIG_PORT_SET 4 170 171 #define DSP_COMMAND_GALAXY_8 8 172 #define GALAXY_COMMAND_GET_TYPE 5 173 174 #define DSP_COMMAND_GALAXY_9 9 175 #define GALAXY_COMMAND_WSSMODE 0 176 #define GALAXY_COMMAND_SB8MODE 1 177 178 #define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE 179 #define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE 180 181 struct snd_galaxy { 182 void __iomem *port; 183 void __iomem *config_port; 184 void __iomem *wss_port; 185 u32 config; 186 struct resource *res_port; 187 struct resource *res_config_port; 188 struct resource *res_wss_port; 189 }; 190 191 static u32 config[SNDRV_CARDS]; 192 static u8 wss_config[SNDRV_CARDS]; 193 194 static int snd_galaxy_match(struct device *dev, unsigned int n) 195 { 196 if (!enable[n]) 197 return 0; 198 199 switch (port[n]) { 200 case SNDRV_AUTO_PORT: 201 dev_err(dev, "please specify port\n"); 202 return 0; 203 case 0x220: 204 config[n] |= GALAXY_CONFIG_SBA_220; 205 break; 206 case 0x240: 207 config[n] |= GALAXY_CONFIG_SBA_240; 208 break; 209 case 0x260: 210 config[n] |= GALAXY_CONFIG_SBA_260; 211 break; 212 case 0x280: 213 config[n] |= GALAXY_CONFIG_SBA_280; 214 break; 215 default: 216 dev_err(dev, "invalid port %#lx\n", port[n]); 217 return 0; 218 } 219 220 switch (wss_port[n]) { 221 case SNDRV_AUTO_PORT: 222 dev_err(dev, "please specify wss_port\n"); 223 return 0; 224 case 0x530: 225 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530; 226 break; 227 case 0x604: 228 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604; 229 break; 230 case 0xe80: 231 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80; 232 break; 233 case 0xf40: 234 config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40; 235 break; 236 default: 237 dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]); 238 return 0; 239 } 240 241 switch (irq[n]) { 242 case SNDRV_AUTO_IRQ: 243 dev_err(dev, "please specify irq\n"); 244 return 0; 245 case 7: 246 wss_config[n] |= WSS_CONFIG_IRQ_7; 247 break; 248 case 2: 249 irq[n] = 9; 250 fallthrough; 251 case 9: 252 wss_config[n] |= WSS_CONFIG_IRQ_9; 253 break; 254 case 10: 255 wss_config[n] |= WSS_CONFIG_IRQ_10; 256 break; 257 case 11: 258 wss_config[n] |= WSS_CONFIG_IRQ_11; 259 break; 260 default: 261 dev_err(dev, "invalid IRQ %d\n", irq[n]); 262 return 0; 263 } 264 265 switch (dma1[n]) { 266 case SNDRV_AUTO_DMA: 267 dev_err(dev, "please specify dma1\n"); 268 return 0; 269 case 0: 270 wss_config[n] |= WSS_CONFIG_DMA_0; 271 break; 272 case 1: 273 wss_config[n] |= WSS_CONFIG_DMA_1; 274 break; 275 case 3: 276 wss_config[n] |= WSS_CONFIG_DMA_3; 277 break; 278 default: 279 dev_err(dev, "invalid playback DMA %d\n", dma1[n]); 280 return 0; 281 } 282 283 if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) { 284 dma2[n] = -1; 285 goto mpu; 286 } 287 288 wss_config[n] |= WSS_CONFIG_DUPLEX; 289 switch (dma2[n]) { 290 case 0: 291 break; 292 case 1: 293 if (dma1[n] == 0) 294 break; 295 fallthrough; 296 default: 297 dev_err(dev, "invalid capture DMA %d\n", dma2[n]); 298 return 0; 299 } 300 301 mpu: 302 switch (mpu_port[n]) { 303 case SNDRV_AUTO_PORT: 304 dev_warn(dev, "mpu_port not specified; not using MPU-401\n"); 305 mpu_port[n] = -1; 306 goto fm; 307 case 0x300: 308 config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300; 309 break; 310 case 0x330: 311 config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330; 312 break; 313 default: 314 dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]); 315 return 0; 316 } 317 318 switch (mpu_irq[n]) { 319 case SNDRV_AUTO_IRQ: 320 dev_warn(dev, "mpu_irq not specified: using polling mode\n"); 321 mpu_irq[n] = -1; 322 break; 323 case 2: 324 mpu_irq[n] = 9; 325 fallthrough; 326 case 9: 327 config[n] |= GALAXY_CONFIG_MPUIRQ_2; 328 break; 329 #ifdef AZT1605 330 case 3: 331 config[n] |= GALAXY_CONFIG_MPUIRQ_3; 332 break; 333 #endif 334 case 5: 335 config[n] |= GALAXY_CONFIG_MPUIRQ_5; 336 break; 337 case 7: 338 config[n] |= GALAXY_CONFIG_MPUIRQ_7; 339 break; 340 #ifdef AZT2316 341 case 10: 342 config[n] |= GALAXY_CONFIG_MPUIRQ_10; 343 break; 344 #endif 345 default: 346 dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]); 347 return 0; 348 } 349 350 if (mpu_irq[n] == irq[n]) { 351 dev_err(dev, "cannot share IRQ between WSS and MPU-401\n"); 352 return 0; 353 } 354 355 fm: 356 switch (fm_port[n]) { 357 case SNDRV_AUTO_PORT: 358 dev_warn(dev, "fm_port not specified: not using OPL3\n"); 359 fm_port[n] = -1; 360 break; 361 case 0x388: 362 break; 363 default: 364 dev_err(dev, "illegal FM port %#lx\n", fm_port[n]); 365 return 0; 366 } 367 368 config[n] |= GALAXY_CONFIG_GAME_ENABLE; 369 return 1; 370 } 371 372 static int galaxy_init(struct snd_galaxy *galaxy, u8 *type) 373 { 374 u8 major; 375 u8 minor; 376 int err; 377 378 err = dsp_reset(galaxy->port); 379 if (err < 0) 380 return err; 381 382 err = dsp_get_version(galaxy->port, &major, &minor); 383 if (err < 0) 384 return err; 385 386 if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR) 387 return -ENODEV; 388 389 err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8); 390 if (err < 0) 391 return err; 392 393 err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE); 394 if (err < 0) 395 return err; 396 397 err = dsp_get_byte(galaxy->port, type); 398 if (err < 0) 399 return err; 400 401 return 0; 402 } 403 404 static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode) 405 { 406 int err; 407 408 err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9); 409 if (err < 0) 410 return err; 411 412 err = dsp_command(galaxy->port, mode); 413 if (err < 0) 414 return err; 415 416 #ifdef AZT1605 417 /* 418 * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again 419 */ 420 err = dsp_reset(galaxy->port); 421 if (err < 0) 422 return err; 423 #endif 424 425 return 0; 426 } 427 428 static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config) 429 { 430 u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET); 431 int i; 432 433 iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET); 434 for (i = 0; i < GALAXY_CONFIG_SIZE; i++) { 435 iowrite8(config, galaxy->config_port + i); 436 config >>= 8; 437 } 438 iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET); 439 msleep(10); 440 } 441 442 static void galaxy_config(struct snd_galaxy *galaxy, u32 config) 443 { 444 int i; 445 446 for (i = GALAXY_CONFIG_SIZE; i; i--) { 447 u8 tmp = ioread8(galaxy->config_port + i - 1); 448 galaxy->config = (galaxy->config << 8) | tmp; 449 } 450 config |= galaxy->config & GALAXY_CONFIG_MASK; 451 galaxy_set_config(galaxy, config); 452 } 453 454 static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config) 455 { 456 int err; 457 458 err = wss_detect(galaxy->wss_port); 459 if (err < 0) 460 return err; 461 462 wss_set_config(galaxy->wss_port, wss_config); 463 464 err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS); 465 if (err < 0) 466 return err; 467 468 return 0; 469 } 470 471 static void snd_galaxy_free(struct snd_card *card) 472 { 473 struct snd_galaxy *galaxy = card->private_data; 474 475 if (galaxy->wss_port) 476 wss_set_config(galaxy->wss_port, 0); 477 if (galaxy->config_port) 478 galaxy_set_config(galaxy, galaxy->config); 479 } 480 481 static int __snd_galaxy_probe(struct device *dev, unsigned int n) 482 { 483 struct snd_galaxy *galaxy; 484 struct snd_wss *chip; 485 struct snd_card *card; 486 u8 type; 487 int err; 488 489 err = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE, 490 sizeof(*galaxy), &card); 491 if (err < 0) 492 return err; 493 494 card->private_free = snd_galaxy_free; 495 galaxy = card->private_data; 496 497 galaxy->res_port = devm_request_region(dev, port[n], 16, DRV_NAME); 498 if (!galaxy->res_port) { 499 dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n], 500 port[n] + 15); 501 return -EBUSY; 502 } 503 galaxy->port = devm_ioport_map(dev, port[n], 16); 504 if (!galaxy->port) 505 return -ENOMEM; 506 507 err = galaxy_init(galaxy, &type); 508 if (err < 0) { 509 dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]); 510 return err; 511 } 512 dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]); 513 514 galaxy->res_config_port = 515 devm_request_region(dev, port[n] + GALAXY_PORT_CONFIG, 16, 516 DRV_NAME); 517 if (!galaxy->res_config_port) { 518 dev_err(dev, "could not grab ports %#lx-%#lx\n", 519 port[n] + GALAXY_PORT_CONFIG, 520 port[n] + GALAXY_PORT_CONFIG + 15); 521 return -EBUSY; 522 } 523 galaxy->config_port = 524 devm_ioport_map(dev, port[n] + GALAXY_PORT_CONFIG, 16); 525 if (!galaxy->config_port) 526 return -ENOMEM; 527 galaxy_config(galaxy, config[n]); 528 529 galaxy->res_wss_port = devm_request_region(dev, wss_port[n], 4, DRV_NAME); 530 if (!galaxy->res_wss_port) { 531 dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n], 532 wss_port[n] + 3); 533 return -EBUSY; 534 } 535 galaxy->wss_port = devm_ioport_map(dev, wss_port[n], 4); 536 if (!galaxy->wss_port) 537 return -ENOMEM; 538 539 err = galaxy_wss_config(galaxy, wss_config[n]); 540 if (err < 0) { 541 dev_err(dev, "could not configure WSS\n"); 542 return err; 543 } 544 545 strcpy(card->driver, DRV_NAME); 546 strcpy(card->shortname, DRV_NAME); 547 sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d", 548 card->shortname, port[n], wss_port[n], irq[n], dma1[n], 549 dma2[n]); 550 551 err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n], 552 dma2[n], WSS_HW_DETECT, 0, &chip); 553 if (err < 0) 554 return err; 555 556 err = snd_wss_pcm(chip, 0); 557 if (err < 0) 558 return err; 559 560 err = snd_wss_mixer(chip); 561 if (err < 0) 562 return err; 563 564 err = snd_wss_timer(chip, 0); 565 if (err < 0) 566 return err; 567 568 if (mpu_port[n] >= 0) { 569 err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, 570 mpu_port[n], 0, mpu_irq[n], NULL); 571 if (err < 0) 572 return err; 573 } 574 575 if (fm_port[n] >= 0) { 576 struct snd_opl3 *opl3; 577 578 err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2, 579 OPL3_HW_AUTO, 0, &opl3); 580 if (err < 0) { 581 dev_err(dev, "no OPL device at %#lx\n", fm_port[n]); 582 return err; 583 } 584 err = snd_opl3_timer_new(opl3, 1, 2); 585 if (err < 0) 586 return err; 587 588 err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); 589 if (err < 0) 590 return err; 591 } 592 593 err = snd_card_register(card); 594 if (err < 0) 595 return err; 596 597 dev_set_drvdata(dev, card); 598 return 0; 599 } 600 601 static int snd_galaxy_probe(struct device *dev, unsigned int n) 602 { 603 return snd_card_free_on_error(dev, __snd_galaxy_probe(dev, n)); 604 } 605 606 static struct isa_driver snd_galaxy_driver = { 607 .match = snd_galaxy_match, 608 .probe = snd_galaxy_probe, 609 610 .driver = { 611 .name = DEV_NAME 612 } 613 }; 614 615 module_isa_driver(snd_galaxy_driver, SNDRV_CARDS); 616
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.