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 | (joystick ? 0x40 : 0), 0xF388); 160 161 if (pas_irq < 0 || pas_irq > 15) 162 { 163 printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); 164 hw_config->irq=-1; 165 ok = 0; 166 } 167 else 168 { 169 int_ptrs = pas_read(0xF38A); 170 int_ptrs = (int_ptrs & 0xf0) | irq_bits[pas_irq]; 171 pas_write(int_ptrs, 0xF38A); 172 if (!irq_bits[pas_irq]) 173 { 174 printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); 175 hw_config->irq=-1; 176 ok = 0; 177 } 178 else 179 { 180 if (request_irq(pas_irq, pasintr, 0, "PAS16",hw_config) < 0) { 181 printk(KERN_ERR "PAS16: Cannot allocate IRQ %d\n",pas_irq); 182 hw_config->irq=-1; 183 ok = 0; 184 } 185 } 186 } 187 188 if (hw_config->dma < 0 || hw_config->dma > 7) 189 { 190 printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); 191 hw_config->dma=-1; 192 ok = 0; 193 } 194 else 195 { 196 pas_write(dma_bits[hw_config->dma], 0xF389); 197 if (!dma_bits[hw_config->dma]) 198 { 199 printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); 200 hw_config->dma=-1; 201 ok = 0; 202 } 203 else 204 { 205 if (sound_alloc_dma(hw_config->dma, "PAS16")) 206 { 207 printk(KERN_ERR "pas2_card.c: Can't allocate DMA channel\n"); 208 hw_config->dma=-1; 209 ok = 0; 210 } 211 } 212 } 213 214 /* 215 * This fixes the timing problems of the PAS due to the Symphony chipset 216 * as per Media Vision. Only define this if your PAS doesn't work correctly. 217 */ 218 219 if(symphony) 220 { 221 outb((0x05), 0xa8); 222 outb((0x60), 0xa9); 223 } 224 225 if(broken_bus_clock) 226 pas_write(0x01 | 0x10 | 0x20 | 0x04, 0x8388); 227 else 228 /* 229 * pas_write(0x01, 0x8388); 230 */ 231 pas_write(0x01 | 0x10 | 0x20, 0x8388); 232 233 pas_write(0x18, 0x838A); /* ??? */ 234 pas_write(0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ 235 pas_write(8, 0xBF8A); 236 237 mix_write(0x80 | 5, 0x078B); 238 mix_write(5, 0x078B); 239 240 { 241 struct address_info *sb_config; 242 243 sb_config = &cfg2; 244 if (sb_config->io_base) 245 { 246 unsigned char irq_dma; 247 248 /* 249 * Turn on Sound Blaster compatibility 250 * bit 1 = SB emulation 251 * bit 0 = MPU401 emulation (CDPC only :-( ) 252 */ 253 254 pas_write(0x02, 0xF788); 255 256 /* 257 * "Emulation address" 258 */ 259 260 pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); 261 pas_sb_base = sb_config->io_base; 262 263 if (!sb_dma_bits[sb_config->dma]) 264 printk(KERN_ERR "PAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); 265 266 if (!sb_irq_bits[sb_config->irq]) 267 printk(KERN_ERR "PAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); 268 269 irq_dma = sb_dma_bits[sb_config->dma] | 270 sb_irq_bits[sb_config->irq]; 271 272 pas_write(irq_dma, 0xFB8A); 273 } 274 else 275 pas_write(0x00, 0xF788); 276 } 277 278 if (!ok) 279 printk(KERN_WARNING "PAS16: Driver not enabled\n"); 280 281 return ok; 282} 283 284static int __init detect_pas_hw(struct address_info *hw_config) 285{ 286 unsigned char board_id, foo; 287 288 /* 289 * WARNING: Setting an option like W:1 or so that disables warm boot reset 290 * of the card will screw up this detect code something fierce. Adding code 291 * to handle this means possibly interfering with other cards on the bus if 292 * you have something on base port 0x388. SO be forewarned. 293 */ 294 295 outb((0xBC), 0x9A01); /* Activate first board */ 296 outb((hw_config->io_base >> 2), 0x9A01); /* Set base address */ 297 pas_translate_code = hw_config->io_base - 0x388; 298 pas_write(1, 0xBF88); /* Select one wait states */ 299 300 board_id = pas_read(0x0B8B); 301 302 if (board_id == 0xff) 303 return 0; 304 305 /* 306 * We probably have a PAS-series board, now check for a PAS16-series board 307 * by trying to change the board revision bits. PAS16-series hardware won't 308 * let you do this - the bits are read-only. 309 */ 310 311 foo = board_id ^ 0xe0; 312 313 pas_write(foo, 0x0B8B); 314 foo = pas_read(0x0B8B); 315 pas_write(board_id, 0x0B8B); 316 317 if (board_id != foo) 318 return 0; 319 320 pas_model = pas_read(0xFF88); 321 322 return pas_model; 323} 324 325static void __init attach_pas_card(struct address_info *hw_config) 326{ 327 pas_irq = hw_config->irq; 328 329 if (detect_pas_hw(hw_config)) 330 { 331 332 if ((pas_model = pas_read(0xFF88))) 333 { 334 char temp[100]; 335 336 sprintf(temp, 337 "%s rev %d", pas_model_names[(int) pas_model], 338 pas_read(0x2789)); 339 conf_printf(temp, hw_config); 340 } 341 if (config_pas_hw(hw_config)) 342 { 343 pas_pcm_init(hw_config); 344 pas_midi_init(); 345 pas_init_mixer(); 346 } 347 } 348} 349 350static inline int __init probe_pas(struct address_info *hw_config) 351{ 352 return detect_pas_hw(hw_config); 353} 354 355static void __exit unload_pas(struct address_info *hw_config) 356{ 357 extern int pas_audiodev; 358 extern int pas2_mididev; 359 360 if (hw_config->dma>0) 361 sound_free_dma(hw_config->dma); 362 if (hw_config->irq>0) 363 free_irq(hw_config->irq, hw_config); 364 365 if(pas_audiodev!=-1) 366 sound_unload_mixerdev(audio_devs[pas_audiodev]->mixer_dev); 367 if(pas2_mididev!=-1) 368 sound_unload_mididev(pas2_mididev); 369 if(pas_audiodev!=-1) 370 sound_unload_audiodev(pas_audiodev); 371} 372 373static int __initdata io = -1; 374static int __initdata irq = -1; 375static int __initdata dma = -1; 376static int __initdata dma16 = -1; /* Set this for modules that need it */ 377 378static int __initdata sb_io = 0; 379static int __initdata sb_irq = -1; 380static int __initdata sb_dma = -1; 381static int __initdata sb_dma16 = -1; 382 383module_param(io, int, 0); 384module_param(irq, int, 0); 385module_param(dma, int, 0); 386module_param(dma16, int, 0); 387 388module_param(sb_io, int, 0); 389module_param(sb_irq, int, 0); 390module_param(sb_dma, int, 0); 391module_param(sb_dma16, int, 0); 392 393module_param(joystick, bool, 0); 394module_param(symphony, bool, 0); 395module_param(broken_bus_clock, bool, 0); 396 397MODULE_LICENSE("GPL"); 398 399static int __init init_pas2(void) 400{ 401 printk(KERN_INFO "Pro Audio Spectrum driver Copyright (C) by Hannu Savolainen 1993-1996\n"); 402 403 cfg.io_base = io; 404 cfg.irq = irq; 405 cfg.dma = dma; 406 cfg.dma2 = dma16; 407 408 cfg2.io_base = sb_io; 409 cfg2.irq = sb_irq; 410 cfg2.dma = sb_dma; 411 cfg2.dma2 = sb_dma16; 412 413 if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) { 414 printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); 415 return -EINVAL; 416 } 417 418 if (!probe_pas(&cfg)) 419 return -ENODEV; 420 attach_pas_card(&cfg); 421 422 return 0; 423} 424 425static void __exit cleanup_pas2(void) 426{ 427 unload_pas(&cfg); 428} 429 430module_init(init_pas2); 431module_exit(cleanup_pas2); 432 433#ifndef MODULE 434static int __init setup_pas2(char *str) 435{ 436 /* io, irq, dma, dma2, sb_io, sb_irq, sb_dma, sb_dma2 */ 437 int ints[9]; 438 439 str = get_options(str, ARRAY_SIZE(ints), ints); 440 441 io = ints[1]; 442 irq = ints[2]; 443 dma = ints[3]; 444 dma16 = ints[4]; 445 446 sb_io = ints[5]; 447 sb_irq = ints[6]; 448 sb_dma = ints[7]; 449 sb_dma16 = ints[8]; 450 451 return 1; 452} 453 454__setup("pas2=", setup_pas2); 455#endif 456