1/* 2 * sound/maui.c 3 * 4 * The low level driver for Turtle Beach Maui and Tropez. 5 * 6 * 7 * Copyright (C) by Hannu Savolainen 1993-1997 8 * 9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 10 * Version 2 (June 1991). See the "COPYING" file distributed with this software 11 * for more info. 12 * 13 * Changes: 14 * Alan Cox General clean up, use kernel IRQ 15 * system 16 * Christoph Hellwig Adapted to module_init/module_exit 17 * Bartlomiej Zolnierkiewicz 18 * Added __init to download_code() 19 * 20 * Status: 21 * Andrew J. Kroll Tested 06/01/1999 with: 22 * * OSWF.MOT File Version: 1.15 23 * * OSWF.MOT File Dated: 09/12/94 24 * * Older versions will cause problems. 25 */ 26 27#include <linux/config.h> 28#include <linux/module.h> 29#include <linux/init.h> 30 31#define USE_SEQ_MACROS 32#define USE_SIMPLE_MACROS 33 34#include "sound_config.h" 35#include "sound_firmware.h" 36 37#include "mpu401.h" 38 39static int maui_base = 0x330; 40 41static volatile int irq_ok = 0; 42static int *maui_osp; 43 44#define HOST_DATA_PORT (maui_base + 2) 45#define HOST_STAT_PORT (maui_base + 3) 46#define HOST_CTRL_PORT (maui_base + 3) 47 48#define STAT_TX_INTR 0x40 49#define STAT_TX_AVAIL 0x20 50#define STAT_TX_IENA 0x10 51#define STAT_RX_INTR 0x04 52#define STAT_RX_AVAIL 0x02 53#define STAT_RX_IENA 0x01 54 55static int (*orig_load_patch) (int dev, int format, const char *addr, 56 int offs, int count, int pmgr_flag) = NULL; 57 58#include "maui_boot.h" 59 60static int maui_wait(int mask) 61{ 62 int i; 63 64 /* 65 * Perform a short initial wait without sleeping 66 */ 67 68 for (i = 0; i < 100; i++) 69 if (inb(HOST_STAT_PORT) & mask) 70 return 1; 71 72 /* 73 * Wait up to 15 seconds with sleeping 74 */ 75 76 for (i = 0; i < 150; i++) { 77 if (inb(HOST_STAT_PORT) & mask) 78 return 1; 79 current->state = TASK_INTERRUPTIBLE; 80 schedule_timeout(HZ / 10); 81 if (signal_pending(current)) 82 return 0; 83 } 84 return 0; 85} 86 87static int maui_read(void) 88{ 89 if (maui_wait(STAT_RX_AVAIL)) 90 return inb(HOST_DATA_PORT); 91 return -1; 92} 93 94static int maui_write(unsigned char data) 95{ 96 if (maui_wait(STAT_TX_AVAIL)) { 97 outb((data), HOST_DATA_PORT); 98 return 1; 99 } 100 printk(KERN_WARNING "Maui: Write timeout\n"); 101 return 0; 102} 103 104static void mauiintr(int irq, void *dev_id, struct pt_regs *dummy) 105{ 106 irq_ok = 1; 107} 108 109static int __init download_code(void) 110{ 111 int i, lines = 0; 112 int eol_seen = 0, done = 0; 113 int skip = 1; 114 115 printk(KERN_INFO "Code download (%d bytes): ", maui_osLen); 116 117 for (i = 0; i < maui_osLen; i++) { 118 if (maui_os[i] != '\r') { 119 if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) { 120 skip = 0; 121 122 if (maui_os[i] == '\n') 123 eol_seen = skip = 1; 124 else if (maui_os[i] == 'S') { 125 if (maui_os[i + 1] == '8') 126 done = 1; 127 if (!maui_write(0xF1)) 128 goto failure; 129 if (!maui_write('S')) 130 goto failure; 131 } else { 132 if (!maui_write(maui_os[i])) 133 goto failure; 134 } 135 136 if (eol_seen) { 137 int c = 0; 138 int n; 139 140 eol_seen = 0; 141 142 for (n = 0; n < 2; n++) { 143 if (maui_wait(STAT_RX_AVAIL)) { 144 c = inb(HOST_DATA_PORT); 145 break; 146 } 147 } 148 if (c != 0x80) { 149 printk("Download not acknowledged\n"); 150 return 0; 151 } 152 else if (!(lines++ % 10)) 153 printk("."); 154 155 if (done) { 156 printk("\n"); 157 printk(KERN_INFO "Download complete\n"); 158 return 1; 159 } 160 } 161 } 162 } 163 } 164 165failure: 166 printk("\n"); 167 printk(KERN_ERR "Download failed!!!\n"); 168 return 0; 169} 170 171static int __init maui_init(int irq) 172{ 173 unsigned char bits; 174 175 switch (irq) { 176 case 9: 177 bits = 0x00; 178 break; 179 case 5: 180 bits = 0x08; 181 break; 182 case 12: 183 bits = 0x10; 184 break; 185 case 15: 186 bits = 0x18; 187 break; 188 189 default: 190 printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq); 191 return 0; 192 } 193 outb((0x00), HOST_CTRL_PORT); /* Reset */ 194 outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */ 195 outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */ 196 outb((0x80), HOST_CTRL_PORT); /* Leave reset */ 197 outb((0x80), HOST_CTRL_PORT); /* Leave reset */ 198 outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */ 199 200#ifdef CONFIG_SMP 201 { 202 int i; 203 for (i = 0; i < 1000000 && !irq_ok; i++) 204 ; 205 if (!irq_ok) 206 return 0; 207 } 208#endif 209 outb((0x80), HOST_CTRL_PORT); /* Leave reset */ 210 211 printk(KERN_INFO "Turtle Beach Maui initialization\n"); 212 213 if (!download_code()) 214 return 0; 215 216 outb((0xE0), HOST_CTRL_PORT); /* Normal operation */ 217 218 /* Select mpu401 mode */ 219 220 maui_write(0xf0); 221 maui_write(1); 222 if (maui_read() != 0x80) { 223 maui_write(0xf0); 224 maui_write(1); 225 if (maui_read() != 0x80) 226 printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n"); 227 } 228 printk(KERN_INFO "Maui initialized OK\n"); 229 return 1; 230} 231 232static int maui_short_wait(int mask) { 233 int i; 234 235 for (i = 0; i < 1000; i++) { 236 if (inb(HOST_STAT_PORT) & mask) { 237 return 1; 238 } 239 } 240 return 0; 241} 242 243static int maui_load_patch(int dev, int format, const char *addr, 244 int offs, int count, int pmgr_flag) 245{ 246 247 struct sysex_info header; 248 unsigned long left, src_offs; 249 int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header; 250 int i; 251 252 if (format == SYSEX_PATCH) /* Handled by midi_synth.c */ 253 return orig_load_patch(dev, format, addr, offs, count, pmgr_flag); 254 255 if (format != MAUI_PATCH) 256 { 257 printk(KERN_WARNING "Maui: Unknown patch format\n"); 258 } 259 if (count < hdr_size) { 260/* printk("Maui error: Patch header too short\n");*/ 261 return -EINVAL; 262 } 263 count -= hdr_size; 264 265 /* 266 * Copy the header from user space but ignore the first bytes which have 267 * been transferred already. 268 */ 269 270 if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs)) 271 return -EFAULT; 272 273 if (count < header.len) { 274 printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len); 275 header.len = count; 276 } 277 left = header.len; 278 src_offs = 0; 279 280 for (i = 0; i < left; i++) { 281 unsigned char data; 282 283 if(get_user(*(unsigned char *) &data, (unsigned char *) &((addr)[hdr_size + i]))) 284 return -EFAULT; 285 if (i == 0 && !(data & 0x80)) 286 return -EINVAL; 287 288 if (maui_write(data) == -1) 289 return -EIO; 290 } 291 292 if ((i = maui_read()) != 0x80) { 293 if (i != -1) 294 printk("Maui: Error status %02x\n", i); 295 return -EIO; 296 } 297 return 0; 298} 299 300static int __init probe_maui(struct address_info *hw_config) 301{ 302 int i; 303 int tmp1, tmp2, ret; 304 305 if (check_region(hw_config->io_base, 8)) 306 return 0; 307 308 maui_base = hw_config->io_base; 309 maui_osp = hw_config->osp; 310 311 if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0) 312 return 0; 313 314 /* 315 * Initialize the processor if necessary 316 */ 317 318 if (maui_osLen > 0) { 319 if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || 320 !maui_write(0x9F) || /* Report firmware version */ 321 !maui_short_wait(STAT_RX_AVAIL) || 322 maui_read() == -1 || maui_read() == -1) 323 if (!maui_init(hw_config->irq)) { 324 free_irq(hw_config->irq, NULL); 325 return 0; 326 } 327 } 328 if (!maui_write(0xCF)) /* Report hardware version */ { 329 printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); 330 free_irq(hw_config->irq, NULL); 331 return 0; 332 } 333 if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) { 334 printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); 335 free_irq(hw_config->irq, NULL); 336 return 0; 337 } 338 if (tmp1 == 0xff || tmp2 == 0xff) { 339 free_irq(hw_config->irq, NULL); 340 return 0; 341 } 342 printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); 343 344 if (!maui_write(0x9F)) /* Report firmware version */ 345 return 0; 346 if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) 347 return 0; 348 349 printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2); 350 351 if (!maui_write(0x85)) /* Report free DRAM */ 352 return 0; 353 tmp1 = 0; 354 for (i = 0; i < 4; i++) { 355 tmp1 |= maui_read() << (7 * i); 356 } 357 printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024); 358 359 for (i = 0; i < 1000; i++) 360 if (probe_mpu401(hw_config)) 361 break; 362 363 ret = probe_mpu401(hw_config); 364 365 if (ret) 366 request_region(hw_config->io_base + 2, 6, "Maui"); 367 368 return ret; 369} 370 371static void __init attach_maui(struct address_info *hw_config) 372{ 373 int this_dev; 374 375 conf_printf("Maui", hw_config); 376 377 hw_config->irq *= -1; 378 hw_config->name = "Maui"; 379 attach_mpu401(hw_config, THIS_MODULE); 380 381 if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { 382 struct synth_operations *synth; 383 384 this_dev = hw_config->slots[1]; 385 386 /* 387 * Intercept patch loading calls so that they can be handled 388 * by the Maui driver. 389 */ 390 391 synth = midi_devs[this_dev]->converter; 392 synth->id = "MAUI"; 393 394 if (synth != NULL) { 395 orig_load_patch = synth->load_patch; 396 synth->load_patch = &maui_load_patch; 397 } else 398 printk(KERN_ERR "Maui: Can't install patch loader\n"); 399 } 400} 401 402static void __exit unload_maui(struct address_info *hw_config) 403{ 404 int irq = hw_config->irq; 405 release_region(hw_config->io_base + 2, 6); 406 unload_mpu401(hw_config); 407 408 if (irq < 0) 409 irq = -irq; 410 if (irq > 0) 411 free_irq(irq, NULL); 412} 413 414static int fw_load = 0; 415 416static struct address_info cfg; 417 418static int __initdata io = -1; 419static int __initdata irq = -1; 420 421MODULE_PARM(io,"i"); 422MODULE_PARM(irq,"i"); 423 424/* 425 * Install a Maui card. Needs mpu401 loaded already. 426 */ 427 428static int __init init_maui(void) 429{ 430 printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n"); 431 432 cfg.io_base = io; 433 cfg.irq = irq; 434 435 if (cfg.io_base == -1 || cfg.irq == -1) { 436 printk(KERN_INFO "maui: irq and io must be set.\n"); 437 return -EINVAL; 438 } 439 440 if (maui_os == NULL) { 441 fw_load = 1; 442 maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os); 443 } 444 if (probe_maui(&cfg) == 0) 445 return -ENODEV; 446 attach_maui(&cfg); 447 448 return 0; 449} 450 451static void __exit cleanup_maui(void) 452{ 453 if (fw_load && maui_os) 454 vfree(maui_os); 455 unload_maui(&cfg); 456} 457 458module_init(init_maui); 459module_exit(cleanup_maui); 460 461#ifndef MODULE 462static int __init setup_maui(char *str) 463{ 464 /* io, irq */ 465 int ints[3]; 466 467 str = get_options(str, ARRAY_SIZE(ints), ints); 468 469 io = ints[1]; 470 irq = ints[2]; 471 472 return 1; 473} 474 475__setup("maui=", setup_maui); 476#endif 477MODULE_LICENSE("GPL"); 478