1/* 2 * sound/oss/trix.c 3 * 4 * Low level driver for the MediaTrix AudioTrix Pro 5 * (MT-0002-PC Control Chip) 6 * 7 * 8 * Copyright (C) by Hannu Savolainen 1993-1997 9 * 10 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 11 * Version 2 (June 1991). See the "COPYING" file distributed with this software 12 * for more info. 13 * 14 * Changes 15 * Alan Cox Modularisation, cleanup. 16 * Christoph Hellwig Adapted to module_init/module_exit 17 * Arnaldo C. de Melo Got rid of attach_uart401 18 */ 19 20#include <linux/init.h> 21#include <linux/module.h> 22 23#include "sound_config.h" 24#include "sb.h" 25#include "sound_firmware.h" 26 27#include "ad1848.h" 28#include "mpu401.h" 29 30#include "trix_boot.h" 31 32static int mpu; 33 34static bool joystick; 35 36static unsigned char trix_read(int addr) 37{ 38 outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ 39 return inb(0x391); /* MT-0002-PC ASIC data */ 40} 41 42static void trix_write(int addr, int data) 43{ 44 outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ 45 outb(((unsigned char) data), 0x391); /* MT-0002-PC ASIC data */ 46} 47 48static void download_boot(int base) 49{ 50 int i = 0, n = trix_boot_len; 51 52 if (trix_boot_len == 0) 53 return; 54 55 trix_write(0xf8, 0x00); /* ??????? */ 56 outb((0x01), base + 6); /* Clear the internal data pointer */ 57 outb((0x00), base + 6); /* Restart */ 58 59 /* 60 * Write the boot code to the RAM upload/download register. 61 * Each write increments the internal data pointer. 62 */ 63 outb((0x01), base + 6); /* Clear the internal data pointer */ 64 outb((0x1A), 0x390); /* Select RAM download/upload port */ 65 66 for (i = 0; i < n; i++) 67 outb((trix_boot[i]), 0x391); 68 for (i = n; i < 10016; i++) /* Clear up to first 16 bytes of data RAM */ 69 outb((0x00), 0x391); 70 outb((0x00), base + 6); /* Reset */ 71 outb((0x50), 0x390); /* ?????? */ 72 73} 74 75static int trix_set_wss_port(struct address_info *hw_config) 76{ 77 unsigned char addr_bits; 78 79 if (trix_read(0x15) != 0x71) /* No ASIC signature */ 80 { 81 MDB(printk(KERN_ERR "No AudioTrix ASIC signature found\n")); 82 return 0; 83 } 84 85 /* 86 * Reset some registers. 87 */ 88 89 trix_write(0x13, 0); 90 trix_write(0x14, 0); 91 92 /* 93 * Configure the ASIC to place the codec to the proper I/O location 94 */ 95 96 switch (hw_config->io_base) 97 { 98 case 0x530: 99 addr_bits = 0; 100 break; 101 case 0x604: 102 addr_bits = 1; 103 break; 104 case 0xE80: 105 addr_bits = 2; 106 break; 107 case 0xF40: 108 addr_bits = 3; 109 break; 110 default: 111 return 0; 112 } 113 114 trix_write(0x19, (trix_read(0x19) & 0x03) | addr_bits); 115 return 1; 116} 117 118/* 119 * Probe and attach routines for the Windows Sound System mode of 120 * AudioTrix Pro 121 */ 122 123static int __init init_trix_wss(struct address_info *hw_config) 124{ 125 static unsigned char dma_bits[4] = { 126 1, 2, 0, 3 127 }; 128 struct resource *ports; 129 int config_port = hw_config->io_base + 0; 130 int dma1 = hw_config->dma, dma2 = hw_config->dma2; 131 int old_num_mixers = num_mixers; 132 u8 config, bits; 133 int ret; 134 135 switch(hw_config->irq) { 136 case 7: 137 bits = 8; 138 break; 139 case 9: 140 bits = 0x10; 141 break; 142 case 10: 143 bits = 0x18; 144 break; 145 case 11: 146 bits = 0x20; 147 break; 148 default: 149 printk(KERN_ERR "AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); 150 return 0; 151 } 152 153 switch (dma1) { 154 case 0: 155 case 1: 156 case 3: 157 break; 158 default: 159 printk(KERN_ERR "AudioTrix: Bad WSS DMA %d\n", dma1); 160 return 0; 161 } 162 163 switch (dma2) { 164 case -1: 165 case 0: 166 case 1: 167 case 3: 168 break; 169 default: 170 printk(KERN_ERR "AudioTrix: Bad capture DMA %d\n", dma2); 171 return 0; 172 } 173 174 /* 175 * Check if the IO port returns valid signature. The original MS Sound 176 * system returns 0x04 while some cards (AudioTrix Pro for example) 177 * return 0x00. 178 */ 179 ports = request_region(hw_config->io_base + 4, 4, "ad1848"); 180 if (!ports) { 181 printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); 182 return 0; 183 } 184 185 if (!request_region(hw_config->io_base, 4, "MSS config")) { 186 printk(KERN_ERR "AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); 187 release_region(hw_config->io_base + 4, 4); 188 return 0; 189 } 190 191 if (!trix_set_wss_port(hw_config)) 192 goto fail; 193 194 config = inb(hw_config->io_base + 3); 195 196 if ((config & 0x3f) != 0x00) 197 { 198 MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x\n", hw_config->io_base)); 199 goto fail; 200 } 201 202 /* 203 * Check that DMA0 is not in use with a 8 bit board. 204 */ 205 206 if (dma1 == 0 && config & 0x80) 207 { 208 printk(KERN_ERR "AudioTrix: Can't use DMA0 with a 8 bit card slot\n"); 209 goto fail; 210 } 211 if (hw_config->irq > 9 && config & 0x80) 212 { 213 printk(KERN_ERR "AudioTrix: Can't use IRQ%d with a 8 bit card slot\n", hw_config->irq); 214 goto fail; 215 } 216 217 ret = ad1848_detect(ports, NULL, hw_config->osp); 218 if (!ret) 219 goto fail; 220 221 if (joystick==1) 222 trix_write(0x15, 0x80); 223 224 /* 225 * Set the IRQ and DMA addresses. 226 */ 227 228 outb((bits | 0x40), config_port); 229 230 if (dma2 == -1 || dma2 == dma1) 231 { 232 bits |= dma_bits[dma1]; 233 dma2 = dma1; 234 } 235 else 236 { 237 unsigned char tmp; 238 239 tmp = trix_read(0x13) & ~30; 240 trix_write(0x13, tmp | 0x80 | (dma1 << 4)); 241 242 tmp = trix_read(0x14) & ~30; 243 trix_write(0x14, tmp | 0x80 | (dma2 << 4)); 244 } 245 246 outb((bits), config_port); /* Write IRQ+DMA setup */ 247 248 hw_config->slots[0] = ad1848_init("AudioTrix Pro", ports, 249 hw_config->irq, 250 dma1, 251 dma2, 252 0, 253 hw_config->osp, 254 THIS_MODULE); 255 256 if (num_mixers > old_num_mixers) /* Mixer got installed */ 257 { 258 AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); /* Line in */ 259 AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); 260 AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* OPL4 */ 261 AD1848_REROUTE(SOUND_MIXER_SPEAKER, SOUND_MIXER_ALTPCM); /* SB */ 262 } 263 return 1; 264 265fail: 266 release_region(hw_config->io_base, 4); 267 release_region(hw_config->io_base + 4, 4); 268 return 0; 269} 270 271static int __init probe_trix_sb(struct address_info *hw_config) 272{ 273 274 int tmp; 275 unsigned char conf; 276 extern int sb_be_quiet; 277 int old_quiet; 278 static signed char irq_translate[] = { 279 -1, -1, -1, 0, 1, 2, -1, 3 280 }; 281 282 if (trix_boot_len == 0) 283 return 0; /* No boot code -> no fun */ 284 285 if ((hw_config->io_base & 0xffffff8f) != 0x200) 286 return 0; 287 288 tmp = hw_config->irq; 289 if (tmp > 7) 290 return 0; 291 if (irq_translate[tmp] == -1) 292 return 0; 293 294 tmp = hw_config->dma; 295 if (tmp != 1 && tmp != 3) 296 return 0; 297 298 if (!request_region(hw_config->io_base, 16, "soundblaster")) { 299 printk(KERN_ERR "AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); 300 return 0; 301 } 302 303 conf = 0x84; /* DMA and IRQ enable */ 304 conf |= hw_config->io_base & 0x70; /* I/O address bits */ 305 conf |= irq_translate[hw_config->irq]; 306 if (hw_config->dma == 3) 307 conf |= 0x08; 308 trix_write(0x1b, conf); 309 310 download_boot(hw_config->io_base); 311 312 hw_config->name = "AudioTrix SB"; 313 if (!sb_dsp_detect(hw_config, 0, 0, NULL)) { 314 release_region(hw_config->io_base, 16); 315 return 0; 316 } 317 318 hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; 319 320 /* Prevent false alarms */ 321 old_quiet = sb_be_quiet; 322 sb_be_quiet = 1; 323 324 sb_dsp_init(hw_config, THIS_MODULE); 325 326 sb_be_quiet = old_quiet; 327 return 1; 328} 329 330static int __init probe_trix_mpu(struct address_info *hw_config) 331{ 332 unsigned char conf; 333 static int irq_bits[] = { 334 -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 335 }; 336 337 if (hw_config->irq > 9) 338 { 339 printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); 340 return 0; 341 } 342 if (irq_bits[hw_config->irq] == -1) 343 { 344 printk(KERN_ERR "AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); 345 return 0; 346 } 347 switch (hw_config->io_base) 348 { 349 case 0x330: 350 conf = 0x00; 351 break; 352 case 0x370: 353 conf = 0x04; 354 break; 355 case 0x3b0: 356 conf = 0x08; 357 break; 358 case 0x3f0: 359 conf = 0x0c; 360 break; 361 default: 362 return 0; /* Invalid port */ 363 } 364 365 conf |= irq_bits[hw_config->irq] << 4; 366 trix_write(0x19, (trix_read(0x19) & 0x83) | conf); 367 hw_config->name = "AudioTrix Pro"; 368 return probe_uart401(hw_config, THIS_MODULE); 369} 370 371static void __exit unload_trix_wss(struct address_info *hw_config) 372{ 373 int dma2 = hw_config->dma2; 374 375 if (dma2 == -1) 376 dma2 = hw_config->dma; 377 378 release_region(0x390, 2); 379 release_region(hw_config->io_base, 4); 380 381 ad1848_unload(hw_config->io_base + 4, 382 hw_config->irq, 383 hw_config->dma, 384 dma2, 385 0); 386 sound_unload_audiodev(hw_config->slots[0]); 387} 388 389static inline void __exit unload_trix_mpu(struct address_info *hw_config) 390{ 391 unload_uart401(hw_config); 392} 393 394static inline void __exit unload_trix_sb(struct address_info *hw_config) 395{ 396 sb_dsp_unload(hw_config, mpu); 397} 398 399static struct address_info cfg; 400static struct address_info cfg2; 401static struct address_info cfg_mpu; 402 403static int sb; 404static int fw_load; 405 406static int __initdata io = -1; 407static int __initdata irq = -1; 408static int __initdata dma = -1; 409static int __initdata dma2 = -1; /* Set this for modules that need it */ 410static int __initdata sb_io = -1; 411static int __initdata sb_dma = -1; 412static int __initdata sb_irq = -1; 413static int __initdata mpu_io = -1; 414static int __initdata mpu_irq = -1; 415 416module_param(io, int, 0); 417module_param(irq, int, 0); 418module_param(dma, int, 0); 419module_param(dma2, int, 0); 420module_param(sb_io, int, 0); 421module_param(sb_dma, int, 0); 422module_param(sb_irq, int, 0); 423module_param(mpu_io, int, 0); 424module_param(mpu_irq, int, 0); 425module_param(joystick, bool, 0); 426 427static int __init init_trix(void) 428{ 429 printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); 430 431 cfg.io_base = io; 432 cfg.irq = irq; 433 cfg.dma = dma; 434 cfg.dma2 = dma2; 435 436 cfg2.io_base = sb_io; 437 cfg2.irq = sb_irq; 438 cfg2.dma = sb_dma; 439 440 cfg_mpu.io_base = mpu_io; 441 cfg_mpu.irq = mpu_irq; 442 443 if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { 444 printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); 445 return -EINVAL; 446 } 447 448 if (cfg2.io_base != -1 && (cfg2.irq == -1 || cfg2.dma == -1)) { 449 printk(KERN_INFO "CONFIG_SB_IRQ and CONFIG_SB_DMA must be specified if SB_IO is set.\n"); 450 return -EINVAL; 451 } 452 if (cfg_mpu.io_base != -1 && cfg_mpu.irq == -1) { 453 printk(KERN_INFO "CONFIG_MPU_IRQ must be specified if MPU_IO is set.\n"); 454 return -EINVAL; 455 } 456 if (!trix_boot) 457 { 458 fw_load = 1; 459 trix_boot_len = mod_firmware_load("/etc/sound/trxpro.bin", 460 (char **) &trix_boot); 461 } 462 463 if (!request_region(0x390, 2, "AudioTrix")) { 464 printk(KERN_ERR "AudioTrix: Config port I/O conflict\n"); 465 return -ENODEV; 466 } 467 468 if (!init_trix_wss(&cfg)) { 469 release_region(0x390, 2); 470 return -ENODEV; 471 } 472 473 /* 474 * We must attach in the right order to get the firmware 475 * loaded up in time. 476 */ 477 478 if (cfg2.io_base != -1) { 479 sb = probe_trix_sb(&cfg2); 480 } 481 482 if (cfg_mpu.io_base != -1) 483 mpu = probe_trix_mpu(&cfg_mpu); 484 485 return 0; 486} 487 488static void __exit cleanup_trix(void) 489{ 490 if (fw_load) 491 vfree(trix_boot); 492 if (sb) 493 unload_trix_sb(&cfg2); 494 if (mpu) 495 unload_trix_mpu(&cfg_mpu); 496 unload_trix_wss(&cfg); 497} 498 499module_init(init_trix); 500module_exit(cleanup_trix); 501 502#ifndef MODULE 503static int __init setup_trix (char *str) 504{ 505 /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, mpu_io, mpu_irq */ 506 int ints[9]; 507 508 str = get_options(str, ARRAY_SIZE(ints), ints); 509 510 io = ints[1]; 511 irq = ints[2]; 512 dma = ints[3]; 513 dma2 = ints[4]; 514 sb_io = ints[5]; 515 sb_irq = ints[6]; 516 sb_dma = ints[6]; 517 mpu_io = ints[7]; 518 mpu_irq = ints[8]; 519 520 return 1; 521} 522 523__setup("trix=", setup_trix); 524#endif 525MODULE_LICENSE("GPL"); 526