1/* 2 * sound/oss/pas2_card.c 3 * 4 * Detection routine for the Pro Audio Spectrum cards. 5 */ 6 7#include <linux/init.h> 8#include <linux/interrupt.h> 9#include <linux/module.h> 10#include <linux/spinlock.h> 11#include "sound_config.h" 12 13#include "pas2.h" 14#include "sb.h" 15 16static unsigned char dma_bits[] = { 17 4, 1, 2, 3, 0, 5, 6, 7 18}; 19 20static unsigned char irq_bits[] = { 21 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 22}; 23 24static unsigned char sb_irq_bits[] = { 25 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 26 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 27}; 28 29static unsigned char sb_dma_bits[] = { 30 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 31}; 32 33/* 34 * The Address Translation code is used to convert I/O register addresses to 35 * be relative to the given base -register 36 */ 37 38int pas_translate_code = 0; 39static int pas_intr_mask; 40static int pas_irq; 41static int pas_sb_base; 42DEFINE_SPINLOCK(pas_lock); 43#ifndef CONFIG_PAS_JOYSTICK 44static int joystick; 45#else 46static int joystick = 1; 47#endif 48#ifdef SYMPHONY_PAS 49static int symphony = 1; 50#else 51static int symphony; 52#endif 53#ifdef BROKEN_BUS_CLOCK 54static int broken_bus_clock = 1; 55#else 56static int broken_bus_clock; 57#endif 58 59static struct address_info cfg; 60static struct address_info cfg2; 61 62char pas_model = 0; 63static char *pas_model_names[] = { 64 "", 65 "Pro AudioSpectrum+", 66 "CDPC", 67 "Pro AudioSpectrum 16", 68 "Pro AudioSpectrum 16D" 69}; 70 71/* 72 * pas_read() and pas_write() are equivalents of inb and outb 73 * These routines perform the I/O address translation required 74 * to support other than the default base address 75 */ 76 77extern void mix_write(unsigned char data, int ioaddr); 78 79unsigned char pas_read(int ioaddr) 80{ 81 return inb(ioaddr + pas_translate_code); 82} 83 84void pas_write(unsigned char data, int ioaddr) 85{ 86 outb((data), ioaddr + pas_translate_code); 87} 88 89/******************* Begin of the Interrupt Handler ********************/ 90 91static irqreturn_t pasintr(int irq, void *dev_id) 92{ 93 int status; 94 95 status = pas_read(0x0B89); 96 pas_write(status, 0x0B89); /* Clear interrupt */ 97 98 if (status & 0x08) 99 { 100 pas_pcm_interrupt(status, 1); 101 status &= ~0x08; 102 } 103 if (status & 0x10) 104 { 105 pas_midi_interrupt(); 106 status &= ~0x10; 107 } 108 return IRQ_HANDLED; 109} 110 111int pas_set_intr(int mask) 112{ 113 if (!mask) 114 return 0; 115 116 pas_intr_mask |= mask; 117 118 pas_write(pas_intr_mask, 0x0B8B); 119 return 0; 120} 121 122int pas_remove_intr(int mask) 123{ 124 if (!mask) 125 return 0; 126 127 pas_intr_mask &= ~mask; 128 pas_write(pas_intr_mask, 0x0B8B); 129 130 return 0; 131} 132 133/******************* End of the Interrupt handler **********************/ 134 135/******************* Begin of the Initialization Code ******************/ 136 137static int __init config_pas_hw(struct address_info *hw_config) 138{ 139 char ok = 1; 140 unsigned int_ptrs; /* scsi/sound interrupt pointers */ 141 142 pas_irq = hw_config->irq; 143 144 pas_write(0x00, 0x0B8B); 145 pas_write(0x36, 0x138B); 146 pas_write(0x36, 0x1388); 147 pas_write(0, 0x1388); 148 pas_write(0x74, 0x138B); 149 pas_write(0x74, 0x1389); 150 pas_write(0, 0x1389); 151 152 pas_write(0x80 | 0x40 | 0x20 | 1, 0x0B8A); 153 pas_write(0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); 154 pas_write(0x01 | 0x02 | 0x04 | 0x10 /* 155 * | 156 * 0x80 157 */ , 0xB88); 158 159 pas_write(0x80 160 | joystick?0x40:0 161 ,0xF388); 162 163 if (pas_irq < 0 || pas_irq > 15) 164 { 165 printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); 166 hw_config->irq=-1; 167 ok = 0; 168 } 169 else 170 { 171 int_ptrs = pas_read(0xF38A); 172 int_ptrs = (int_ptrs & 0xf0) | irq_bits[pas_irq]; 173 pas_write(int_ptrs, 0xF38A); 174 if (!irq_bits[pas_irq]) 175 { 176 printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); 177 hw_config->irq=-1; 178 ok = 0; 179 } 180 else 181 { 182 if (request_irq(pas_irq, pasintr, 0, "PAS16",hw_config) < 0) { 183 printk(KERN_ERR "PAS16: Cannot allocate IRQ %d\n",pas_irq); 184 hw_config->irq=-1; 185 ok = 0; 186 } 187 } 188 } 189 190 if (hw_config->dma < 0 || hw_config->dma > 7) 191 { 192 printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); 193 hw_config->dma=-1; 194 ok = 0; 195 } 196 else 197 { 198 pas_write(dma_bits[hw_config->dma], 0xF389); 199 if (!dma_bits[hw_config->dma]) 200 { 201 printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); 202 hw_config->dma=-1; 203 ok = 0; 204 } 205 else 206 { 207 if (sound_alloc_dma(hw_config->dma, "PAS16")) 208 { 209 printk(KERN_ERR "pas2_card.c: Can't allocate DMA channel\n"); 210 hw_config->dma=-1; 211 ok = 0; 212 } 213 } 214 } 215 216 /* 217 * This fixes the timing problems of the PAS due to the Symphony chipset 218 * as per Media Vision. Only define this if your PAS doesn't work correctly. 219 */ 220 221 if(symphony) 222 { 223 outb((0x05), 0xa8); 224 outb((0x60), 0xa9); 225 } 226 227 if(broken_bus_clock) 228 pas_write(0x01 | 0x10 | 0x20 | 0x04, 0x8388); 229 else 230 /* 231 * pas_write(0x01, 0x8388); 232 */ 233 pas_write(0x01 | 0x10 | 0x20, 0x8388); 234 235 pas_write(0x18, 0x838A); /* ??? */ 236 pas_write(0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ 237 pas_write(8, 0xBF8A); 238 239 mix_write(0x80 | 5, 0x078B); 240 mix_write(5, 0x078B); 241 242 { 243 struct address_info *sb_config; 244 245 sb_config = &cfg2; 246 if (sb_config->io_base) 247 { 248 unsigned char irq_dma; 249 250 /* 251 * Turn on Sound Blaster compatibility 252 * bit 1 = SB emulation 253 * bit 0 = MPU401 emulation (CDPC only :-( ) 254 */ 255 256 pas_write(0x02, 0xF788); 257 258 /* 259 * "Emulation address" 260 */ 261 262 pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); 263 pas_sb_base = sb_config->io_base; 264 265 if (!sb_dma_bits[sb_config->dma]) 266 printk(KERN_ERR "PAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); 267 268 if (!sb_irq_bits[sb_config->irq]) 269 printk(KERN_ERR "PAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); 270 271 irq_dma = sb_dma_bits[sb_config->dma] | 272 sb_irq_bits[sb_config->irq]; 273 274 pas_write(irq_dma, 0xFB8A); 275 } 276 else 277 pas_write(0x00, 0xF788); 278 } 279 280 if (!ok) 281 printk(KERN_WARNING "PAS16: Driver not enabled\n"); 282 283 return ok; 284} 285 286static int __init detect_pas_hw(struct address_info *hw_config) 287{ 288 unsigned char board_id, foo; 289 290 /* 291 * WARNING: Setting an option like W:1 or so that disables warm boot reset 292 * of the card will screw up this detect code something fierce. Adding code 293 * to handle this means possibly interfering with other cards on the bus if 294 * you have something on base port 0x388. SO be forewarned. 295 */ 296 297 outb((0xBC), 0x9A01); /* Activate first board */ 298 outb((hw_config->io_base >> 2), 0x9A01); /* Set base address */ 299 pas_translate_code = hw_config->io_base - 0x388; 300 pas_write(1, 0xBF88); /* Select one wait states */ 301 302 board_id = pas_read(0x0B8B); 303 304 if (board_id == 0xff) 305 return 0; 306 307 /* 308 * We probably have a PAS-series board, now check for a PAS16-series board 309 * by trying to change the board revision bits. PAS16-series hardware won't 310 * let you do this - the bits are read-only. 311 */ 312 313 foo = board_id ^ 0xe0; 314 315 pas_write(foo, 0x0B8B); 316 foo = pas_read(0x0B8B); 317 pas_write(board_id, 0x0B8B); 318 319 if (board_id != foo) 320 return 0; 321 322 pas_model = pas_read(0xFF88); 323 324 return pas_model; 325} 326 327static void __init attach_pas_card(struct address_info *hw_config) 328{ 329 pas_irq = hw_config->irq; 330 331 if (detect_pas_hw(hw_config)) 332 { 333 334 if ((pas_model = pas_read(0xFF88))) 335 { 336 char temp[100]; 337 338 sprintf(temp, 339 "%s rev %d", pas_model_names[(int) pas_model], 340 pas_read(0x2789)); 341 conf_printf(temp, hw_config); 342 } 343 if (config_pas_hw(hw_config)) 344 { 345 pas_pcm_init(hw_config); 346 pas_midi_init(); 347 pas_init_mixer(); 348 } 349 } 350} 351 352static inline int __init probe_pas(struct address_info *hw_config) 353{ 354 return detect_pas_hw(hw_config); 355} 356 357static void __exit unload_pas(struct address_info *hw_config) 358{ 359 extern int pas_audiodev; 360 extern int pas2_mididev; 361 362 if (hw_config->dma>0) 363 sound_free_dma(hw_config->dma); 364 if (hw_config->irq>0) 365 free_irq(hw_config->irq, hw_config); 366 367 if(pas_audiodev!=-1) 368 sound_unload_mixerdev(audio_devs[pas_audiodev]->mixer_dev); 369 if(pas2_mididev!=-1) 370 sound_unload_mididev(pas2_mididev); 371 if(pas_audiodev!=-1) 372 sound_unload_audiodev(pas_audiodev); 373} 374 375static int __initdata io = -1; 376static int __initdata irq = -1; 377static int __initdata dma = -1; 378static int __initdata dma16 = -1; /* Set this for modules that need it */ 379 380static int __initdata sb_io = 0; 381static int __initdata sb_irq = -1; 382static int __initdata sb_dma = -1; 383static int __initdata sb_dma16 = -1; 384 385module_param(io, int, 0); 386module_param(irq, int, 0); 387module_param(dma, int, 0); 388module_param(dma16, int, 0); 389 390module_param(sb_io, int, 0); 391module_param(sb_irq, int, 0); 392module_param(sb_dma, int, 0); 393module_param(sb_dma16, int, 0); 394 395module_param(joystick, bool, 0); 396module_param(symphony, bool, 0); 397module_param(broken_bus_clock, bool, 0); 398 399MODULE_LICENSE("GPL"); 400 401static int __init init_pas2(void) 402{ 403 printk(KERN_INFO "Pro Audio Spectrum driver Copyright (C) by Hannu Savolainen 1993-1996\n"); 404 405 cfg.io_base = io; 406 cfg.irq = irq; 407 cfg.dma = dma; 408 cfg.dma2 = dma16; 409 410 cfg2.io_base = sb_io; 411 cfg2.irq = sb_irq; 412 cfg2.dma = sb_dma; 413 cfg2.dma2 = sb_dma16; 414 415 if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { 416 printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); 417 return -EINVAL; 418 } 419 420 if (!probe_pas(&cfg)) 421 return -ENODEV; 422 attach_pas_card(&cfg); 423 424 return 0; 425} 426 427static void __exit cleanup_pas2(void) 428{ 429 unload_pas(&cfg); 430} 431 432module_init(init_pas2); 433module_exit(cleanup_pas2); 434 435#ifndef MODULE 436static int __init setup_pas2(char *str) 437{ 438 /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, sb_dma2 */ 439 int ints[9]; 440 441 str = get_options(str, ARRAY_SIZE(ints), ints); 442 443 io = ints[1]; 444 irq = ints[2]; 445 dma = ints[3]; 446 dma16 = ints[4]; 447 448 sb_io = ints[5]; 449 sb_irq = ints[6]; 450 sb_dma = ints[7]; 451 sb_dma16 = ints[8]; 452 453 return 1; 454} 455 456__setup("pas2=", setup_pas2); 457#endif 458