| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /*  -*- linux-c -*- | 
|  | 2 | * | 
|  | 3 | * sound/wavfront.c | 
|  | 4 | * | 
|  | 5 | * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus) | 
|  | 6 | * | 
|  | 7 | * This driver supports the onboard wavetable synthesizer (an ICS2115), | 
|  | 8 | * including patch, sample and program loading and unloading, conversion | 
|  | 9 | * of GUS patches during loading, and full user-level access to all | 
|  | 10 | * WaveFront commands. It tries to provide semi-intelligent patch and | 
|  | 11 | * sample management as well. | 
|  | 12 | * | 
|  | 13 | * It also provides support for the ICS emulation of an MPU-401.  Full | 
|  | 14 | * support for the ICS emulation's "virtual MIDI mode" is provided in | 
|  | 15 | * wf_midi.c. | 
|  | 16 | * | 
|  | 17 | * Support is also provided for the Tropez Plus' onboard FX processor, | 
|  | 18 | * a Yamaha YSS225. Currently, code exists to configure the YSS225, | 
|  | 19 | * and there is an interface allowing tweaking of any of its memory | 
|  | 20 | * addresses. However, I have been unable to decipher the logical | 
|  | 21 | * positioning of the configuration info for various effects, so for | 
|  | 22 | * now, you just get the YSS225 in the same state as Turtle Beach's | 
|  | 23 | * "SETUPSND.EXE" utility leaves it. | 
|  | 24 | * | 
|  | 25 | * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co], | 
|  | 26 | * This chip also controls the configuration of the card: the wavefront | 
|  | 27 | * synth is logical unit 4. | 
|  | 28 | * | 
|  | 29 | * | 
|  | 30 | * Supported devices: | 
|  | 31 | * | 
|  | 32 | *   /dev/dsp                      - using cs4232+ad1848 modules, OSS compatible | 
|  | 33 | *   /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible | 
|  | 34 | *   /dev/synth00                  - raw synth interface | 
|  | 35 | * | 
|  | 36 | ********************************************************************** | 
|  | 37 | * | 
|  | 38 | * Copyright (C) by Paul Barton-Davis 1998 | 
|  | 39 | * | 
|  | 40 | * Some portions of this file are taken from work that is | 
|  | 41 | * copyright (C) by Hannu Savolainen 1993-1996 | 
|  | 42 | * | 
|  | 43 | * Although the relevant code here is all new, the handling of | 
|  | 44 | * sample/alias/multi- samples is entirely based on a driver by Matt | 
|  | 45 | * Martin and Rutger Nijlunsing which demonstrated how to get things | 
|  | 46 | * to work correctly. The GUS patch loading code has been almost | 
|  | 47 | * unaltered by me, except to fit formatting and function names in the | 
|  | 48 | * rest of the file. Many thanks to them. | 
|  | 49 | * | 
|  | 50 | * Appreciation and thanks to Hannu Savolainen for his early work on the Maui | 
|  | 51 | * driver, and answering a few questions while this one was developed. | 
|  | 52 | * | 
|  | 53 | * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their | 
|  | 54 | * complete lack of help in developing this driver, and in particular | 
|  | 55 | * for their utter silence in response to questions about undocumented | 
|  | 56 | * aspects of configuring a WaveFront soundcard, particularly the | 
|  | 57 | * effects processor. | 
|  | 58 | * | 
|  | 59 | * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $ | 
|  | 60 | * | 
|  | 61 | * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | 
|  | 62 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | 
|  | 63 | * for more info. | 
|  | 64 | * | 
|  | 65 | * Changes: | 
|  | 66 | * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> | 
|  | 67 | *		Added some __init and __initdata to entries in yss225.c | 
|  | 68 | */ | 
|  | 69 |  | 
|  | 70 | #include <linux/module.h> | 
|  | 71 |  | 
|  | 72 | #include <linux/kernel.h> | 
|  | 73 | #include <linux/init.h> | 
|  | 74 | #include <linux/sched.h> | 
|  | 75 | #include <linux/smp_lock.h> | 
|  | 76 | #include <linux/ptrace.h> | 
|  | 77 | #include <linux/fcntl.h> | 
|  | 78 | #include <linux/syscalls.h> | 
|  | 79 | #include <linux/ioport.h> | 
|  | 80 | #include <linux/spinlock.h> | 
|  | 81 | #include <linux/interrupt.h> | 
|  | 82 | #include <linux/config.h> | 
|  | 83 |  | 
|  | 84 | #include <linux/delay.h> | 
|  | 85 |  | 
|  | 86 | #include "sound_config.h" | 
|  | 87 |  | 
|  | 88 | #include <linux/wavefront.h> | 
|  | 89 |  | 
|  | 90 | #define _MIDI_SYNTH_C_ | 
|  | 91 | #define MIDI_SYNTH_NAME	"WaveFront MIDI" | 
|  | 92 | #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT | 
|  | 93 | #include "midi_synth.h" | 
|  | 94 |  | 
|  | 95 | /* Compile-time control of the extent to which OSS is supported. | 
|  | 96 |  | 
|  | 97 | I consider /dev/sequencer to be an anachronism, but given its | 
|  | 98 | widespread usage by various Linux MIDI software, it seems worth | 
|  | 99 | offering support to it if it's not too painful. Instead of using | 
|  | 100 | /dev/sequencer, I recommend: | 
|  | 101 |  | 
|  | 102 | for synth programming and patch loading: /dev/synthNN | 
|  | 103 | for kernel-synchronized MIDI sequencing: the ALSA sequencer | 
|  | 104 | for direct MIDI control: /dev/midiNN | 
|  | 105 |  | 
|  | 106 | I have never tried static compilation into the kernel. The #if's | 
|  | 107 | for this are really just notes to myself about what the code is | 
|  | 108 | for. | 
|  | 109 | */ | 
|  | 110 |  | 
|  | 111 | #define OSS_SUPPORT_SEQ            0x1  /* use of /dev/sequencer */ | 
|  | 112 | #define OSS_SUPPORT_STATIC_INSTALL 0x2  /* static compilation into kernel */ | 
|  | 113 |  | 
|  | 114 | #define OSS_SUPPORT_LEVEL          0x1  /* just /dev/sequencer for now */ | 
|  | 115 |  | 
|  | 116 | #if    OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 117 | static int (*midi_load_patch) (int devno, int format, const char __user *addr, | 
|  | 118 | int offs, int count, int pmgr_flag) = NULL; | 
|  | 119 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 120 |  | 
|  | 121 | /* if WF_DEBUG not defined, no run-time debugging messages will | 
|  | 122 | be available via the debug flag setting. Given the current | 
|  | 123 | beta state of the driver, this will remain set until a future | 
|  | 124 | version. | 
|  | 125 | */ | 
|  | 126 |  | 
|  | 127 | #define WF_DEBUG 1 | 
|  | 128 |  | 
|  | 129 | #ifdef WF_DEBUG | 
|  | 130 |  | 
|  | 131 | /* Thank goodness for gcc's preprocessor ... */ | 
|  | 132 |  | 
|  | 133 | #define DPRINT(cond, format, args...) \ | 
|  | 134 | if ((dev.debug & (cond)) == (cond)) { \ | 
|  | 135 | printk (KERN_DEBUG LOGNAME format, ## args); \ | 
|  | 136 | } | 
|  | 137 | #else | 
|  | 138 | #define DPRINT(cond, format, args...) | 
|  | 139 | #endif | 
|  | 140 |  | 
|  | 141 | #define LOGNAME "WaveFront: " | 
|  | 142 |  | 
|  | 143 | /* bitmasks for WaveFront status port value */ | 
|  | 144 |  | 
|  | 145 | #define STAT_RINTR_ENABLED	0x01 | 
|  | 146 | #define STAT_CAN_READ		0x02 | 
|  | 147 | #define STAT_INTR_READ		0x04 | 
|  | 148 | #define STAT_WINTR_ENABLED	0x10 | 
|  | 149 | #define STAT_CAN_WRITE		0x20 | 
|  | 150 | #define STAT_INTR_WRITE		0x40 | 
|  | 151 |  | 
|  | 152 | /*** Module-accessible parameters ***************************************/ | 
|  | 153 |  | 
|  | 154 | int wf_raw;     /* we normally check for "raw state" to firmware | 
|  | 155 | loading. if set, then during driver loading, the | 
|  | 156 | state of the board is ignored, and we reset the | 
|  | 157 | board and load the firmware anyway. | 
|  | 158 | */ | 
|  | 159 |  | 
|  | 160 | static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in | 
|  | 161 | whatever state it is when the driver is loaded. | 
|  | 162 | The default is to download the microprogram and | 
|  | 163 | associated coefficients to set it up for "default" | 
|  | 164 | operation, whatever that means. | 
|  | 165 | */ | 
|  | 166 |  | 
|  | 167 | static int debug_default;  /* you can set this to control debugging | 
|  | 168 | during driver loading. it takes any combination | 
|  | 169 | of the WF_DEBUG_* flags defined in | 
|  | 170 | wavefront.h | 
|  | 171 | */ | 
|  | 172 |  | 
|  | 173 | /* XXX this needs to be made firmware and hardware version dependent */ | 
|  | 174 |  | 
|  | 175 | static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed | 
|  | 176 | version of the WaveFront OS | 
|  | 177 | */ | 
|  | 178 |  | 
|  | 179 | static int wait_polls = 2000; /* This is a number of tries we poll the | 
|  | 180 | status register before resorting to sleeping. | 
|  | 181 | WaveFront being an ISA card each poll takes | 
|  | 182 | about 1.2us. So before going to | 
|  | 183 | sleep we wait up to 2.4ms in a loop. | 
|  | 184 | */ | 
|  | 185 |  | 
|  | 186 | static int sleep_length = HZ/100; /* This says how long we're going to | 
|  | 187 | sleep between polls. | 
|  | 188 | 10ms sounds reasonable for fast response. | 
|  | 189 | */ | 
|  | 190 |  | 
|  | 191 | static int sleep_tries = 50;       /* Wait for status 0.5 seconds total. */ | 
|  | 192 |  | 
|  | 193 | static int reset_time = 2; /* hundreths of a second we wait after a HW reset for | 
|  | 194 | the expected interrupt. | 
|  | 195 | */ | 
|  | 196 |  | 
|  | 197 | static int ramcheck_time = 20;    /* time in seconds to wait while ROM code | 
|  | 198 | checks on-board RAM. | 
|  | 199 | */ | 
|  | 200 |  | 
|  | 201 | static int osrun_time = 10;  /* time in seconds we wait for the OS to | 
|  | 202 | start running. | 
|  | 203 | */ | 
|  | 204 |  | 
|  | 205 | module_param(wf_raw, int, 0); | 
|  | 206 | module_param(fx_raw, int, 0); | 
|  | 207 | module_param(debug_default, int, 0); | 
|  | 208 | module_param(wait_polls, int, 0); | 
|  | 209 | module_param(sleep_length, int, 0); | 
|  | 210 | module_param(sleep_tries, int, 0); | 
|  | 211 | module_param(ospath, charp, 0); | 
|  | 212 | module_param(reset_time, int, 0); | 
|  | 213 | module_param(ramcheck_time, int, 0); | 
|  | 214 | module_param(osrun_time, int, 0); | 
|  | 215 |  | 
|  | 216 | /***************************************************************************/ | 
|  | 217 |  | 
|  | 218 | /* Note: because this module doesn't export any symbols, this really isn't | 
|  | 219 | a global variable, even if it looks like one. I was quite confused by | 
|  | 220 | this when I started writing this as a (newer) module -- pbd. | 
|  | 221 | */ | 
|  | 222 |  | 
|  | 223 | struct wf_config { | 
|  | 224 | int devno;            /* device number from kernel */ | 
|  | 225 | int irq;              /* "you were one, one of the few ..." */ | 
|  | 226 | int base;             /* low i/o port address */ | 
|  | 227 |  | 
|  | 228 | #define mpu_data_port    base | 
|  | 229 | #define mpu_command_port base + 1 /* write semantics */ | 
|  | 230 | #define mpu_status_port  base + 1 /* read semantics */ | 
|  | 231 | #define data_port        base + 2 | 
|  | 232 | #define status_port      base + 3 /* read semantics */ | 
|  | 233 | #define control_port     base + 3 /* write semantics  */ | 
|  | 234 | #define block_port       base + 4 /* 16 bit, writeonly */ | 
|  | 235 | #define last_block_port  base + 6 /* 16 bit, writeonly */ | 
|  | 236 |  | 
|  | 237 | /* FX ports. These are mapped through the ICS2115 to the YS225. | 
|  | 238 | The ICS2115 takes care of flipping the relevant pins on the | 
|  | 239 | YS225 so that access to each of these ports does the right | 
|  | 240 | thing. Note: these are NOT documented by Turtle Beach. | 
|  | 241 | */ | 
|  | 242 |  | 
|  | 243 | #define fx_status       base + 8 | 
|  | 244 | #define fx_op           base + 8 | 
|  | 245 | #define fx_lcr          base + 9 | 
|  | 246 | #define fx_dsp_addr     base + 0xa | 
|  | 247 | #define fx_dsp_page     base + 0xb | 
|  | 248 | #define fx_dsp_lsb      base + 0xc | 
|  | 249 | #define fx_dsp_msb      base + 0xd | 
|  | 250 | #define fx_mod_addr     base + 0xe | 
|  | 251 | #define fx_mod_data     base + 0xf | 
|  | 252 |  | 
|  | 253 | volatile int irq_ok;               /* set by interrupt handler */ | 
|  | 254 | volatile int irq_cnt;              /* ditto */ | 
|  | 255 | int opened;                        /* flag, holds open(2) mode */ | 
|  | 256 | char debug;                        /* debugging flags */ | 
|  | 257 | int freemem;                       /* installed RAM, in bytes */ | 
|  | 258 |  | 
|  | 259 | int synth_dev;                     /* devno for "raw" synth */ | 
|  | 260 | int mididev;                       /* devno for internal MIDI */ | 
|  | 261 | int ext_mididev;                   /* devno for external MIDI */ | 
|  | 262 | int fx_mididev;                    /* devno for FX MIDI interface */ | 
|  | 263 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 264 | int oss_dev;                      /* devno for OSS sequencer synth */ | 
|  | 265 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 266 |  | 
|  | 267 | char fw_version[2];                /* major = [0], minor = [1] */ | 
|  | 268 | char hw_version[2];                /* major = [0], minor = [1] */ | 
|  | 269 | char israw;                        /* needs Motorola microcode */ | 
|  | 270 | char has_fx;                       /* has FX processor (Tropez+) */ | 
|  | 271 | char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */ | 
|  | 272 | char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */ | 
|  | 273 | char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */ | 
|  | 274 | int samples_used;                  /* how many */ | 
|  | 275 | char interrupts_on;                /* h/w MPU interrupts enabled ? */ | 
|  | 276 | char rom_samples_rdonly;           /* can we write on ROM samples */ | 
|  | 277 | wait_queue_head_t interrupt_sleeper; | 
|  | 278 | } dev; | 
|  | 279 |  | 
|  | 280 | static DEFINE_SPINLOCK(lock); | 
|  | 281 | static int  detect_wffx(void); | 
|  | 282 | static int  wffx_ioctl (wavefront_fx_info *); | 
|  | 283 | static int  wffx_init (void); | 
|  | 284 |  | 
|  | 285 | static int wavefront_delete_sample (int sampnum); | 
|  | 286 | static int wavefront_find_free_sample (void); | 
|  | 287 |  | 
|  | 288 | /* From wf_midi.c */ | 
|  | 289 |  | 
|  | 290 | extern int  virtual_midi_enable  (void); | 
|  | 291 | extern int  virtual_midi_disable (void); | 
|  | 292 | extern int  detect_wf_mpu (int, int); | 
|  | 293 | extern int  install_wf_mpu (void); | 
|  | 294 | extern int  uninstall_wf_mpu (void); | 
|  | 295 |  | 
|  | 296 | typedef struct { | 
|  | 297 | int cmd; | 
|  | 298 | char *action; | 
|  | 299 | unsigned int read_cnt; | 
|  | 300 | unsigned int write_cnt; | 
|  | 301 | int need_ack; | 
|  | 302 | } wavefront_command; | 
|  | 303 |  | 
|  | 304 | static struct { | 
|  | 305 | int errno; | 
|  | 306 | const char *errstr; | 
|  | 307 | } wavefront_errors[] = { | 
|  | 308 | { 0x01, "Bad sample number" }, | 
|  | 309 | { 0x02, "Out of sample memory" }, | 
|  | 310 | { 0x03, "Bad patch number" }, | 
|  | 311 | { 0x04, "Error in number of voices" }, | 
|  | 312 | { 0x06, "Sample load already in progress" }, | 
|  | 313 | { 0x0B, "No sample load request pending" }, | 
|  | 314 | { 0x0E, "Bad MIDI channel number" }, | 
|  | 315 | { 0x10, "Download Record Error" }, | 
|  | 316 | { 0x80, "Success" }, | 
|  | 317 | { 0 } | 
|  | 318 | }; | 
|  | 319 |  | 
|  | 320 | #define NEEDS_ACK 1 | 
|  | 321 |  | 
|  | 322 | static wavefront_command wavefront_commands[] = { | 
|  | 323 | { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK }, | 
|  | 324 | { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0}, | 
|  | 325 | { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK }, | 
|  | 326 | { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 }, | 
|  | 327 | { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK }, | 
|  | 328 | { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 }, | 
|  | 329 | { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK }, | 
|  | 330 | { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK }, | 
|  | 331 | { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 }, | 
|  | 332 | { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK }, | 
|  | 333 | { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK }, | 
|  | 334 | { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK }, | 
|  | 335 | { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK }, | 
|  | 336 | { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 }, | 
|  | 337 | { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 }, | 
|  | 338 | { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 }, | 
|  | 339 | { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 }, | 
|  | 340 | { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 }, | 
|  | 341 | { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 }, | 
|  | 342 | { WFC_DOWNLOAD_SAMPLE, "download sample", | 
|  | 343 | 0, WF_SAMPLE_BYTES, NEEDS_ACK }, | 
|  | 344 | { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK}, | 
|  | 345 | { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header", | 
|  | 346 | 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK }, | 
|  | 347 | { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 }, | 
|  | 348 |  | 
|  | 349 | /* This command requires a variable number of bytes to be written. | 
|  | 350 | There is a hack in wavefront_cmd() to support this. The actual | 
|  | 351 | count is passed in as the read buffer ptr, cast appropriately. | 
|  | 352 | Ugh. | 
|  | 353 | */ | 
|  | 354 |  | 
|  | 355 | { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK }, | 
|  | 356 |  | 
|  | 357 | /* This one is a hack as well. We just read the first byte of the | 
|  | 358 | response, don't fetch an ACK, and leave the rest to the | 
|  | 359 | calling function. Ugly, ugly, ugly. | 
|  | 360 | */ | 
|  | 361 |  | 
|  | 362 | { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 }, | 
|  | 363 | { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias", | 
|  | 364 | 0, WF_ALIAS_BYTES, NEEDS_ACK }, | 
|  | 365 | { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0}, | 
|  | 366 | { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK }, | 
|  | 367 | { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 }, | 
|  | 368 | { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" }, | 
|  | 369 | { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 }, | 
|  | 370 | { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK }, | 
|  | 371 | { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 }, | 
|  | 372 | { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK }, | 
|  | 373 | { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 }, | 
|  | 374 | { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9, | 
|  | 375 | NEEDS_ACK}, | 
|  | 376 | { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0}, | 
|  | 377 | { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel", | 
|  | 378 | 0, 1, NEEDS_ACK }, | 
|  | 379 | { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, | 
|  | 380 | { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", | 
|  | 381 | 32, 0, 0 }, | 
|  | 382 | { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, | 
|  | 383 | { 0x00 } | 
|  | 384 | }; | 
|  | 385 |  | 
|  | 386 | static const char * | 
|  | 387 | wavefront_errorstr (int errnum) | 
|  | 388 |  | 
|  | 389 | { | 
|  | 390 | int i; | 
|  | 391 |  | 
|  | 392 | for (i = 0; wavefront_errors[i].errstr; i++) { | 
|  | 393 | if (wavefront_errors[i].errno == errnum) { | 
|  | 394 | return wavefront_errors[i].errstr; | 
|  | 395 | } | 
|  | 396 | } | 
|  | 397 |  | 
|  | 398 | return "Unknown WaveFront error"; | 
|  | 399 | } | 
|  | 400 |  | 
|  | 401 | static wavefront_command * | 
|  | 402 | wavefront_get_command (int cmd) | 
|  | 403 |  | 
|  | 404 | { | 
|  | 405 | int i; | 
|  | 406 |  | 
|  | 407 | for (i = 0; wavefront_commands[i].cmd != 0; i++) { | 
|  | 408 | if (cmd == wavefront_commands[i].cmd) { | 
|  | 409 | return &wavefront_commands[i]; | 
|  | 410 | } | 
|  | 411 | } | 
|  | 412 |  | 
|  | 413 | return (wavefront_command *) 0; | 
|  | 414 | } | 
|  | 415 |  | 
|  | 416 | static inline int | 
|  | 417 | wavefront_status (void) | 
|  | 418 |  | 
|  | 419 | { | 
|  | 420 | return inb (dev.status_port); | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | static int | 
|  | 424 | wavefront_wait (int mask) | 
|  | 425 |  | 
|  | 426 | { | 
|  | 427 | int i; | 
|  | 428 |  | 
|  | 429 | for (i = 0; i < wait_polls; i++) | 
|  | 430 | if (wavefront_status() & mask) | 
|  | 431 | return 1; | 
|  | 432 |  | 
|  | 433 | for (i = 0; i < sleep_tries; i++) { | 
|  | 434 |  | 
|  | 435 | if (wavefront_status() & mask) { | 
|  | 436 | set_current_state(TASK_RUNNING); | 
|  | 437 | return 1; | 
|  | 438 | } | 
|  | 439 |  | 
|  | 440 | set_current_state(TASK_INTERRUPTIBLE); | 
|  | 441 | schedule_timeout(sleep_length); | 
|  | 442 | if (signal_pending(current)) | 
|  | 443 | break; | 
|  | 444 | } | 
|  | 445 |  | 
|  | 446 | set_current_state(TASK_RUNNING); | 
|  | 447 | return 0; | 
|  | 448 | } | 
|  | 449 |  | 
|  | 450 | static int | 
|  | 451 | wavefront_read (void) | 
|  | 452 |  | 
|  | 453 | { | 
|  | 454 | if (wavefront_wait (STAT_CAN_READ)) | 
|  | 455 | return inb (dev.data_port); | 
|  | 456 |  | 
|  | 457 | DPRINT (WF_DEBUG_DATA, "read timeout.\n"); | 
|  | 458 |  | 
|  | 459 | return -1; | 
|  | 460 | } | 
|  | 461 |  | 
|  | 462 | static int | 
|  | 463 | wavefront_write (unsigned char data) | 
|  | 464 |  | 
|  | 465 | { | 
|  | 466 | if (wavefront_wait (STAT_CAN_WRITE)) { | 
|  | 467 | outb (data, dev.data_port); | 
|  | 468 | return 0; | 
|  | 469 | } | 
|  | 470 |  | 
|  | 471 | DPRINT (WF_DEBUG_DATA, "write timeout.\n"); | 
|  | 472 |  | 
|  | 473 | return -1; | 
|  | 474 | } | 
|  | 475 |  | 
|  | 476 | static int | 
|  | 477 | wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf) | 
|  | 478 |  | 
|  | 479 | { | 
|  | 480 | int ack; | 
|  | 481 | int i; | 
|  | 482 | int c; | 
|  | 483 | wavefront_command *wfcmd; | 
|  | 484 |  | 
|  | 485 | if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) { | 
|  | 486 | printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n", | 
|  | 487 | cmd); | 
|  | 488 | return 1; | 
|  | 489 | } | 
|  | 490 |  | 
|  | 491 | /* Hack to handle the one variable-size write command. See | 
|  | 492 | wavefront_send_multisample() for the other half of this | 
|  | 493 | gross and ugly strategy. | 
|  | 494 | */ | 
|  | 495 |  | 
|  | 496 | if (cmd == WFC_DOWNLOAD_MULTISAMPLE) { | 
|  | 497 | wfcmd->write_cnt = (unsigned int) rbuf; | 
|  | 498 | rbuf = NULL; | 
|  | 499 | } | 
|  | 500 |  | 
|  | 501 | DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n", | 
|  | 502 | cmd, wfcmd->action, wfcmd->read_cnt, | 
|  | 503 | wfcmd->write_cnt, wfcmd->need_ack); | 
|  | 504 |  | 
|  | 505 | if (wavefront_write (cmd)) { | 
|  | 506 | DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request " | 
|  | 507 | "0x%x [%s].\n", | 
|  | 508 | cmd, wfcmd->action); | 
|  | 509 | return 1; | 
|  | 510 | } | 
|  | 511 |  | 
|  | 512 | if (wfcmd->write_cnt > 0) { | 
|  | 513 | DPRINT (WF_DEBUG_DATA, "writing %d bytes " | 
|  | 514 | "for 0x%x\n", | 
|  | 515 | wfcmd->write_cnt, cmd); | 
|  | 516 |  | 
|  | 517 | for (i = 0; i < wfcmd->write_cnt; i++) { | 
|  | 518 | if (wavefront_write (wbuf[i])) { | 
|  | 519 | DPRINT (WF_DEBUG_IO, "bad write for byte " | 
|  | 520 | "%d of 0x%x [%s].\n", | 
|  | 521 | i, cmd, wfcmd->action); | 
|  | 522 | return 1; | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n", | 
|  | 526 | i, wbuf[i]); | 
|  | 527 | } | 
|  | 528 | } | 
|  | 529 |  | 
|  | 530 | if (wfcmd->read_cnt > 0) { | 
|  | 531 | DPRINT (WF_DEBUG_DATA, "reading %d ints " | 
|  | 532 | "for 0x%x\n", | 
|  | 533 | wfcmd->read_cnt, cmd); | 
|  | 534 |  | 
|  | 535 | for (i = 0; i < wfcmd->read_cnt; i++) { | 
|  | 536 |  | 
|  | 537 | if ((c = wavefront_read()) == -1) { | 
|  | 538 | DPRINT (WF_DEBUG_IO, "bad read for byte " | 
|  | 539 | "%d of 0x%x [%s].\n", | 
|  | 540 | i, cmd, wfcmd->action); | 
|  | 541 | return 1; | 
|  | 542 | } | 
|  | 543 |  | 
|  | 544 | /* Now handle errors. Lots of special cases here */ | 
|  | 545 |  | 
|  | 546 | if (c == 0xff) { | 
|  | 547 | if ((c = wavefront_read ()) == -1) { | 
|  | 548 | DPRINT (WF_DEBUG_IO, "bad read for " | 
|  | 549 | "error byte at " | 
|  | 550 | "read byte %d " | 
|  | 551 | "of 0x%x [%s].\n", | 
|  | 552 | i, cmd, | 
|  | 553 | wfcmd->action); | 
|  | 554 | return 1; | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | /* Can you believe this madness ? */ | 
|  | 558 |  | 
|  | 559 | if (c == 1 && | 
|  | 560 | wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { | 
|  | 561 | rbuf[0] = WF_ST_EMPTY; | 
|  | 562 | return (0); | 
|  | 563 |  | 
|  | 564 | } else if (c == 3 && | 
|  | 565 | wfcmd->cmd == WFC_UPLOAD_PATCH) { | 
|  | 566 |  | 
|  | 567 | return 3; | 
|  | 568 |  | 
|  | 569 | } else if (c == 1 && | 
|  | 570 | wfcmd->cmd == WFC_UPLOAD_PROGRAM) { | 
|  | 571 |  | 
|  | 572 | return 1; | 
|  | 573 |  | 
|  | 574 | } else { | 
|  | 575 |  | 
|  | 576 | DPRINT (WF_DEBUG_IO, "error %d (%s) " | 
|  | 577 | "during " | 
|  | 578 | "read for byte " | 
|  | 579 | "%d of 0x%x " | 
|  | 580 | "[%s].\n", | 
|  | 581 | c, | 
|  | 582 | wavefront_errorstr (c), | 
|  | 583 | i, cmd, | 
|  | 584 | wfcmd->action); | 
|  | 585 | return 1; | 
|  | 586 |  | 
|  | 587 | } | 
|  | 588 |  | 
|  | 589 | } else { | 
|  | 590 | rbuf[i] = c; | 
|  | 591 | } | 
|  | 592 |  | 
|  | 593 | DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]); | 
|  | 594 | } | 
|  | 595 | } | 
|  | 596 |  | 
|  | 597 | if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { | 
|  | 598 |  | 
|  | 599 | DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd); | 
|  | 600 |  | 
|  | 601 | /* Some commands need an ACK, but return zero instead | 
|  | 602 | of the standard value. | 
|  | 603 | */ | 
|  | 604 |  | 
|  | 605 | if ((ack = wavefront_read()) == 0) { | 
|  | 606 | ack = WF_ACK; | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 | if (ack != WF_ACK) { | 
|  | 610 | if (ack == -1) { | 
|  | 611 | DPRINT (WF_DEBUG_IO, "cannot read ack for " | 
|  | 612 | "0x%x [%s].\n", | 
|  | 613 | cmd, wfcmd->action); | 
|  | 614 | return 1; | 
|  | 615 |  | 
|  | 616 | } else { | 
|  | 617 | int err = -1; /* something unknown */ | 
|  | 618 |  | 
|  | 619 | if (ack == 0xff) { /* explicit error */ | 
|  | 620 |  | 
|  | 621 | if ((err = wavefront_read ()) == -1) { | 
|  | 622 | DPRINT (WF_DEBUG_DATA, | 
|  | 623 | "cannot read err " | 
|  | 624 | "for 0x%x [%s].\n", | 
|  | 625 | cmd, wfcmd->action); | 
|  | 626 | } | 
|  | 627 | } | 
|  | 628 |  | 
|  | 629 | DPRINT (WF_DEBUG_IO, "0x%x [%s] " | 
|  | 630 | "failed (0x%x, 0x%x, %s)\n", | 
|  | 631 | cmd, wfcmd->action, ack, err, | 
|  | 632 | wavefront_errorstr (err)); | 
|  | 633 |  | 
|  | 634 | return -err; | 
|  | 635 | } | 
|  | 636 | } | 
|  | 637 |  | 
|  | 638 | DPRINT (WF_DEBUG_DATA, "ack received " | 
|  | 639 | "for 0x%x [%s]\n", | 
|  | 640 | cmd, wfcmd->action); | 
|  | 641 | } else { | 
|  | 642 |  | 
|  | 643 | DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need " | 
|  | 644 | "ACK (%d,%d,%d)\n", | 
|  | 645 | cmd, wfcmd->action, wfcmd->read_cnt, | 
|  | 646 | wfcmd->write_cnt, wfcmd->need_ack); | 
|  | 647 | } | 
|  | 648 |  | 
|  | 649 | return 0; | 
|  | 650 |  | 
|  | 651 | } | 
|  | 652 |  | 
|  | 653 | /*********************************************************************** | 
|  | 654 | WaveFront: data munging | 
|  | 655 |  | 
|  | 656 | Things here are weird. All data written to the board cannot | 
|  | 657 | have its most significant bit set. Any data item with values | 
|  | 658 | potentially > 0x7F (127) must be split across multiple bytes. | 
|  | 659 |  | 
|  | 660 | Sometimes, we need to munge numeric values that are represented on | 
|  | 661 | the x86 side as 8-32 bit values. Sometimes, we need to munge data | 
|  | 662 | that is represented on the x86 side as an array of bytes. The most | 
|  | 663 | efficient approach to handling both cases seems to be to use 2 | 
|  | 664 | different functions for munging and 2 for de-munging. This avoids | 
|  | 665 | weird casting and worrying about bit-level offsets. | 
|  | 666 |  | 
|  | 667 | **********************************************************************/ | 
|  | 668 |  | 
|  | 669 | static | 
|  | 670 | unsigned char * | 
|  | 671 | munge_int32 (unsigned int src, | 
|  | 672 | unsigned char *dst, | 
|  | 673 | unsigned int dst_size) | 
|  | 674 | { | 
|  | 675 | int i; | 
|  | 676 |  | 
|  | 677 | for (i = 0;i < dst_size; i++) { | 
|  | 678 | *dst = src & 0x7F;  /* Mask high bit of LSB */ | 
|  | 679 | src = src >> 7;     /* Rotate Right 7 bits  */ | 
|  | 680 | /* Note: we leave the upper bits in place */ | 
|  | 681 |  | 
|  | 682 | dst++; | 
|  | 683 | }; | 
|  | 684 | return dst; | 
|  | 685 | }; | 
|  | 686 |  | 
|  | 687 | static int | 
|  | 688 | demunge_int32 (unsigned char* src, int src_size) | 
|  | 689 |  | 
|  | 690 | { | 
|  | 691 | int i; | 
|  | 692 | int outval = 0; | 
|  | 693 |  | 
|  | 694 | for (i = src_size - 1; i >= 0; i--) { | 
|  | 695 | outval=(outval<<7)+src[i]; | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | return outval; | 
|  | 699 | }; | 
|  | 700 |  | 
|  | 701 | static | 
|  | 702 | unsigned char * | 
|  | 703 | munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size) | 
|  | 704 |  | 
|  | 705 | { | 
|  | 706 | int i; | 
|  | 707 | unsigned int last = dst_size / 2; | 
|  | 708 |  | 
|  | 709 | for (i = 0; i < last; i++) { | 
|  | 710 | *dst++ = src[i] & 0x7f; | 
|  | 711 | *dst++ = src[i] >> 7; | 
|  | 712 | } | 
|  | 713 | return dst; | 
|  | 714 | } | 
|  | 715 |  | 
|  | 716 | static | 
|  | 717 | unsigned char * | 
|  | 718 | demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) | 
|  | 719 |  | 
|  | 720 | { | 
|  | 721 | int i; | 
|  | 722 | unsigned char *end = src + src_bytes; | 
|  | 723 |  | 
|  | 724 | end = src + src_bytes; | 
|  | 725 |  | 
|  | 726 | /* NOTE: src and dst *CAN* point to the same address */ | 
|  | 727 |  | 
|  | 728 | for (i = 0; src != end; i++) { | 
|  | 729 | dst[i] = *src++; | 
|  | 730 | dst[i] |= (*src++)<<7; | 
|  | 731 | } | 
|  | 732 |  | 
|  | 733 | return dst; | 
|  | 734 | } | 
|  | 735 |  | 
|  | 736 | /*********************************************************************** | 
|  | 737 | WaveFront: sample, patch and program management. | 
|  | 738 | ***********************************************************************/ | 
|  | 739 |  | 
|  | 740 | static int | 
|  | 741 | wavefront_delete_sample (int sample_num) | 
|  | 742 |  | 
|  | 743 | { | 
|  | 744 | unsigned char wbuf[2]; | 
|  | 745 | int x; | 
|  | 746 |  | 
|  | 747 | wbuf[0] = sample_num & 0x7f; | 
|  | 748 | wbuf[1] = sample_num >> 7; | 
|  | 749 |  | 
|  | 750 | if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { | 
|  | 751 | dev.sample_status[sample_num] = WF_ST_EMPTY; | 
|  | 752 | } | 
|  | 753 |  | 
|  | 754 | return x; | 
|  | 755 | } | 
|  | 756 |  | 
|  | 757 | static int | 
|  | 758 | wavefront_get_sample_status (int assume_rom) | 
|  | 759 |  | 
|  | 760 | { | 
|  | 761 | int i; | 
|  | 762 | unsigned char rbuf[32], wbuf[32]; | 
|  | 763 | unsigned int    sc_real, sc_alias, sc_multi; | 
|  | 764 |  | 
|  | 765 | /* check sample status */ | 
|  | 766 |  | 
|  | 767 | if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) { | 
|  | 768 | printk (KERN_WARNING LOGNAME "cannot request sample count.\n"); | 
|  | 769 | return -1; | 
|  | 770 | } | 
|  | 771 |  | 
|  | 772 | sc_real = sc_alias = sc_multi = dev.samples_used = 0; | 
|  | 773 |  | 
|  | 774 | for (i = 0; i < WF_MAX_SAMPLE; i++) { | 
|  | 775 |  | 
|  | 776 | wbuf[0] = i & 0x7f; | 
|  | 777 | wbuf[1] = i >> 7; | 
|  | 778 |  | 
|  | 779 | if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { | 
|  | 780 | printk (KERN_WARNING LOGNAME | 
|  | 781 | "cannot identify sample " | 
|  | 782 | "type of slot %d\n", i); | 
|  | 783 | dev.sample_status[i] = WF_ST_EMPTY; | 
|  | 784 | continue; | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); | 
|  | 788 |  | 
|  | 789 | if (assume_rom) { | 
|  | 790 | dev.sample_status[i] |= WF_SLOT_ROM; | 
|  | 791 | } | 
|  | 792 |  | 
|  | 793 | switch (rbuf[0] & WF_ST_MASK) { | 
|  | 794 | case WF_ST_SAMPLE: | 
|  | 795 | sc_real++; | 
|  | 796 | break; | 
|  | 797 | case WF_ST_MULTISAMPLE: | 
|  | 798 | sc_multi++; | 
|  | 799 | break; | 
|  | 800 | case WF_ST_ALIAS: | 
|  | 801 | sc_alias++; | 
|  | 802 | break; | 
|  | 803 | case WF_ST_EMPTY: | 
|  | 804 | break; | 
|  | 805 |  | 
|  | 806 | default: | 
|  | 807 | printk (KERN_WARNING LOGNAME "unknown sample type for " | 
|  | 808 | "slot %d (0x%x)\n", | 
|  | 809 | i, rbuf[0]); | 
|  | 810 | } | 
|  | 811 |  | 
|  | 812 | if (rbuf[0] != WF_ST_EMPTY) { | 
|  | 813 | dev.samples_used++; | 
|  | 814 | } | 
|  | 815 | } | 
|  | 816 |  | 
|  | 817 | printk (KERN_INFO LOGNAME | 
|  | 818 | "%d samples used (%d real, %d aliases, %d multi), " | 
|  | 819 | "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi, | 
|  | 820 | WF_MAX_SAMPLE - dev.samples_used); | 
|  | 821 |  | 
|  | 822 |  | 
|  | 823 | return (0); | 
|  | 824 |  | 
|  | 825 | } | 
|  | 826 |  | 
|  | 827 | static int | 
|  | 828 | wavefront_get_patch_status (void) | 
|  | 829 |  | 
|  | 830 | { | 
|  | 831 | unsigned char patchbuf[WF_PATCH_BYTES]; | 
|  | 832 | unsigned char patchnum[2]; | 
|  | 833 | wavefront_patch *p; | 
|  | 834 | int i, x, cnt, cnt2; | 
|  | 835 |  | 
|  | 836 | for (i = 0; i < WF_MAX_PATCH; i++) { | 
|  | 837 | patchnum[0] = i & 0x7f; | 
|  | 838 | patchnum[1] = i >> 7; | 
|  | 839 |  | 
|  | 840 | if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf, | 
|  | 841 | patchnum)) == 0) { | 
|  | 842 |  | 
|  | 843 | dev.patch_status[i] |= WF_SLOT_FILLED; | 
|  | 844 | p = (wavefront_patch *) patchbuf; | 
|  | 845 | dev.sample_status | 
|  | 846 | [p->sample_number|(p->sample_msb<<7)] |= | 
|  | 847 | WF_SLOT_USED; | 
|  | 848 |  | 
|  | 849 | } else if (x == 3) { /* Bad patch number */ | 
|  | 850 | dev.patch_status[i] = 0; | 
|  | 851 | } else { | 
|  | 852 | printk (KERN_ERR LOGNAME "upload patch " | 
|  | 853 | "error 0x%x\n", x); | 
|  | 854 | dev.patch_status[i] = 0; | 
|  | 855 | return 1; | 
|  | 856 | } | 
|  | 857 | } | 
|  | 858 |  | 
|  | 859 | /* program status has already filled in slot_used bits */ | 
|  | 860 |  | 
|  | 861 | for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { | 
|  | 862 | if (dev.patch_status[i] & WF_SLOT_FILLED) { | 
|  | 863 | cnt++; | 
|  | 864 | } | 
|  | 865 | if (dev.patch_status[i] & WF_SLOT_USED) { | 
|  | 866 | cnt2++; | 
|  | 867 | } | 
|  | 868 |  | 
|  | 869 | } | 
|  | 870 | printk (KERN_INFO LOGNAME | 
|  | 871 | "%d patch slots filled, %d in use\n", cnt, cnt2); | 
|  | 872 |  | 
|  | 873 | return (0); | 
|  | 874 | } | 
|  | 875 |  | 
|  | 876 | static int | 
|  | 877 | wavefront_get_program_status (void) | 
|  | 878 |  | 
|  | 879 | { | 
|  | 880 | unsigned char progbuf[WF_PROGRAM_BYTES]; | 
|  | 881 | wavefront_program prog; | 
|  | 882 | unsigned char prognum; | 
|  | 883 | int i, x, l, cnt; | 
|  | 884 |  | 
|  | 885 | for (i = 0; i < WF_MAX_PROGRAM; i++) { | 
|  | 886 | prognum = i; | 
|  | 887 |  | 
|  | 888 | if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf, | 
|  | 889 | &prognum)) == 0) { | 
|  | 890 |  | 
|  | 891 | dev.prog_status[i] |= WF_SLOT_USED; | 
|  | 892 |  | 
|  | 893 | demunge_buf (progbuf, (unsigned char *) &prog, | 
|  | 894 | WF_PROGRAM_BYTES); | 
|  | 895 |  | 
|  | 896 | for (l = 0; l < WF_NUM_LAYERS; l++) { | 
|  | 897 | if (prog.layer[l].mute) { | 
|  | 898 | dev.patch_status | 
|  | 899 | [prog.layer[l].patch_number] |= | 
|  | 900 | WF_SLOT_USED; | 
|  | 901 | } | 
|  | 902 | } | 
|  | 903 | } else if (x == 1) { /* Bad program number */ | 
|  | 904 | dev.prog_status[i] = 0; | 
|  | 905 | } else { | 
|  | 906 | printk (KERN_ERR LOGNAME "upload program " | 
|  | 907 | "error 0x%x\n", x); | 
|  | 908 | dev.prog_status[i] = 0; | 
|  | 909 | } | 
|  | 910 | } | 
|  | 911 |  | 
|  | 912 | for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { | 
|  | 913 | if (dev.prog_status[i]) { | 
|  | 914 | cnt++; | 
|  | 915 | } | 
|  | 916 | } | 
|  | 917 |  | 
|  | 918 | printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt); | 
|  | 919 |  | 
|  | 920 | return (0); | 
|  | 921 | } | 
|  | 922 |  | 
|  | 923 | static int | 
|  | 924 | wavefront_send_patch (wavefront_patch_info *header) | 
|  | 925 |  | 
|  | 926 | { | 
|  | 927 | unsigned char buf[WF_PATCH_BYTES+2]; | 
|  | 928 | unsigned char *bptr; | 
|  | 929 |  | 
|  | 930 | DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", | 
|  | 931 | header->number); | 
|  | 932 |  | 
|  | 933 | dev.patch_status[header->number] |= WF_SLOT_FILLED; | 
|  | 934 |  | 
|  | 935 | bptr = buf; | 
|  | 936 | bptr = munge_int32 (header->number, buf, 2); | 
|  | 937 | munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); | 
|  | 938 |  | 
|  | 939 | if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) { | 
|  | 940 | printk (KERN_ERR LOGNAME "download patch failed\n"); | 
|  | 941 | return -(EIO); | 
|  | 942 | } | 
|  | 943 |  | 
|  | 944 | return (0); | 
|  | 945 | } | 
|  | 946 |  | 
|  | 947 | static int | 
|  | 948 | wavefront_send_program (wavefront_patch_info *header) | 
|  | 949 |  | 
|  | 950 | { | 
|  | 951 | unsigned char buf[WF_PROGRAM_BYTES+1]; | 
|  | 952 | int i; | 
|  | 953 |  | 
|  | 954 | DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", | 
|  | 955 | header->number); | 
|  | 956 |  | 
|  | 957 | dev.prog_status[header->number] = WF_SLOT_USED; | 
|  | 958 |  | 
|  | 959 | /* XXX need to zero existing SLOT_USED bit for program_status[i] | 
|  | 960 | where `i' is the program that's being (potentially) overwritten. | 
|  | 961 | */ | 
|  | 962 |  | 
|  | 963 | for (i = 0; i < WF_NUM_LAYERS; i++) { | 
|  | 964 | if (header->hdr.pr.layer[i].mute) { | 
|  | 965 | dev.patch_status[header->hdr.pr.layer[i].patch_number] |= | 
|  | 966 | WF_SLOT_USED; | 
|  | 967 |  | 
|  | 968 | /* XXX need to mark SLOT_USED for sample used by | 
|  | 969 | patch_number, but this means we have to load it. Ick. | 
|  | 970 | */ | 
|  | 971 | } | 
|  | 972 | } | 
|  | 973 |  | 
|  | 974 | buf[0] = header->number; | 
|  | 975 | munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); | 
|  | 976 |  | 
|  | 977 | if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) { | 
|  | 978 | printk (KERN_WARNING LOGNAME "download patch failed\n"); | 
|  | 979 | return -(EIO); | 
|  | 980 | } | 
|  | 981 |  | 
|  | 982 | return (0); | 
|  | 983 | } | 
|  | 984 |  | 
|  | 985 | static int | 
|  | 986 | wavefront_freemem (void) | 
|  | 987 |  | 
|  | 988 | { | 
|  | 989 | char rbuf[8]; | 
|  | 990 |  | 
|  | 991 | if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { | 
|  | 992 | printk (KERN_WARNING LOGNAME "can't get memory stats.\n"); | 
|  | 993 | return -1; | 
|  | 994 | } else { | 
|  | 995 | return demunge_int32 (rbuf, 4); | 
|  | 996 | } | 
|  | 997 | } | 
|  | 998 |  | 
|  | 999 | static int | 
|  | 1000 | wavefront_send_sample (wavefront_patch_info *header, | 
|  | 1001 | UINT16 __user *dataptr, | 
|  | 1002 | int data_is_unsigned) | 
|  | 1003 |  | 
|  | 1004 | { | 
|  | 1005 | /* samples are downloaded via a 16-bit wide i/o port | 
|  | 1006 | (you could think of it as 2 adjacent 8-bit wide ports | 
|  | 1007 | but its less efficient that way). therefore, all | 
|  | 1008 | the blocksizes and so forth listed in the documentation, | 
|  | 1009 | and used conventionally to refer to sample sizes, | 
|  | 1010 | which are given in 8-bit units (bytes), need to be | 
|  | 1011 | divided by 2. | 
|  | 1012 | */ | 
|  | 1013 |  | 
|  | 1014 | UINT16 sample_short; | 
|  | 1015 | UINT32 length; | 
|  | 1016 | UINT16 __user *data_end = NULL; | 
|  | 1017 | unsigned int i; | 
|  | 1018 | const int max_blksize = 4096/2; | 
|  | 1019 | unsigned int written; | 
|  | 1020 | unsigned int blocksize; | 
|  | 1021 | int dma_ack; | 
|  | 1022 | int blocknum; | 
|  | 1023 | unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; | 
|  | 1024 | unsigned char *shptr; | 
|  | 1025 | int skip = 0; | 
|  | 1026 | int initial_skip = 0; | 
|  | 1027 |  | 
|  | 1028 | DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " | 
|  | 1029 | "type %d, %d bytes from %p\n", | 
|  | 1030 | header->size ? "" : "header ", | 
|  | 1031 | header->number, header->subkey, | 
|  | 1032 | header->size, | 
|  | 1033 | header->dataptr); | 
|  | 1034 |  | 
|  | 1035 | if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { | 
|  | 1036 | int x; | 
|  | 1037 |  | 
|  | 1038 | if ((x = wavefront_find_free_sample ()) < 0) { | 
|  | 1039 | return -ENOMEM; | 
|  | 1040 | } | 
|  | 1041 | printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x); | 
|  | 1042 | header->number = x; | 
|  | 1043 | } | 
|  | 1044 |  | 
|  | 1045 | if (header->size) { | 
|  | 1046 |  | 
|  | 1047 | /* XXX it's a debatable point whether or not RDONLY semantics | 
|  | 1048 | on the ROM samples should cover just the sample data or | 
|  | 1049 | the sample header. For now, it only covers the sample data, | 
|  | 1050 | so anyone is free at all times to rewrite sample headers. | 
|  | 1051 |  | 
|  | 1052 | My reason for this is that we have the sample headers | 
|  | 1053 | available in the WFB file for General MIDI, and so these | 
|  | 1054 | can always be reset if needed. The sample data, however, | 
|  | 1055 | cannot be recovered without a complete reset and firmware | 
|  | 1056 | reload of the ICS2115, which is a very expensive operation. | 
|  | 1057 |  | 
|  | 1058 | So, doing things this way allows us to honor the notion of | 
|  | 1059 | "RESETSAMPLES" reasonably cheaply. Note however, that this | 
|  | 1060 | is done purely at user level: there is no WFB parser in | 
|  | 1061 | this driver, and so a complete reset (back to General MIDI, | 
|  | 1062 | or theoretically some other configuration) is the | 
|  | 1063 | responsibility of the user level library. | 
|  | 1064 |  | 
|  | 1065 | To try to do this in the kernel would be a little | 
|  | 1066 | crazy: we'd need 158K of kernel space just to hold | 
|  | 1067 | a copy of the patch/program/sample header data. | 
|  | 1068 | */ | 
|  | 1069 |  | 
|  | 1070 | if (dev.rom_samples_rdonly) { | 
|  | 1071 | if (dev.sample_status[header->number] & WF_SLOT_ROM) { | 
|  | 1072 | printk (KERN_ERR LOGNAME "sample slot %d " | 
|  | 1073 | "write protected\n", | 
|  | 1074 | header->number); | 
|  | 1075 | return -EACCES; | 
|  | 1076 | } | 
|  | 1077 | } | 
|  | 1078 |  | 
|  | 1079 | wavefront_delete_sample (header->number); | 
|  | 1080 | } | 
|  | 1081 |  | 
|  | 1082 | if (header->size) { | 
|  | 1083 | dev.freemem = wavefront_freemem (); | 
|  | 1084 |  | 
|  | 1085 | if (dev.freemem < header->size) { | 
|  | 1086 | printk (KERN_ERR LOGNAME | 
|  | 1087 | "insufficient memory to " | 
|  | 1088 | "load %d byte sample.\n", | 
|  | 1089 | header->size); | 
|  | 1090 | return -ENOMEM; | 
|  | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | } | 
|  | 1094 |  | 
|  | 1095 | skip = WF_GET_CHANNEL(&header->hdr.s); | 
|  | 1096 |  | 
|  | 1097 | if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { | 
|  | 1098 | printk (KERN_ERR LOGNAME "channel selection only " | 
|  | 1099 | "possible on 16-bit samples"); | 
|  | 1100 | return -(EINVAL); | 
|  | 1101 | } | 
|  | 1102 |  | 
|  | 1103 | switch (skip) { | 
|  | 1104 | case 0: | 
|  | 1105 | initial_skip = 0; | 
|  | 1106 | skip = 1; | 
|  | 1107 | break; | 
|  | 1108 | case 1: | 
|  | 1109 | initial_skip = 0; | 
|  | 1110 | skip = 2; | 
|  | 1111 | break; | 
|  | 1112 | case 2: | 
|  | 1113 | initial_skip = 1; | 
|  | 1114 | skip = 2; | 
|  | 1115 | break; | 
|  | 1116 | case 3: | 
|  | 1117 | initial_skip = 2; | 
|  | 1118 | skip = 3; | 
|  | 1119 | break; | 
|  | 1120 | case 4: | 
|  | 1121 | initial_skip = 3; | 
|  | 1122 | skip = 4; | 
|  | 1123 | break; | 
|  | 1124 | case 5: | 
|  | 1125 | initial_skip = 4; | 
|  | 1126 | skip = 5; | 
|  | 1127 | break; | 
|  | 1128 | case 6: | 
|  | 1129 | initial_skip = 5; | 
|  | 1130 | skip = 6; | 
|  | 1131 | break; | 
|  | 1132 | } | 
|  | 1133 |  | 
|  | 1134 | DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " | 
|  | 1135 | "initial skip = %d, skip = %d\n", | 
|  | 1136 | WF_GET_CHANNEL (&header->hdr.s), | 
|  | 1137 | initial_skip, skip); | 
|  | 1138 |  | 
|  | 1139 | /* Be safe, and zero the "Unused" bits ... */ | 
|  | 1140 |  | 
|  | 1141 | WF_SET_CHANNEL(&header->hdr.s, 0); | 
|  | 1142 |  | 
|  | 1143 | /* adjust size for 16 bit samples by dividing by two.  We always | 
|  | 1144 | send 16 bits per write, even for 8 bit samples, so the length | 
|  | 1145 | is always half the size of the sample data in bytes. | 
|  | 1146 | */ | 
|  | 1147 |  | 
|  | 1148 | length = header->size / 2; | 
|  | 1149 |  | 
|  | 1150 | /* the data we're sent has not been munged, and in fact, the | 
|  | 1151 | header we have to send isn't just a munged copy either. | 
|  | 1152 | so, build the sample header right here. | 
|  | 1153 | */ | 
|  | 1154 |  | 
|  | 1155 | shptr = &sample_hdr[0]; | 
|  | 1156 |  | 
|  | 1157 | shptr = munge_int32 (header->number, shptr, 2); | 
|  | 1158 |  | 
|  | 1159 | if (header->size) { | 
|  | 1160 | shptr = munge_int32 (length, shptr, 4); | 
|  | 1161 | } | 
|  | 1162 |  | 
|  | 1163 | /* Yes, a 4 byte result doesn't contain all of the offset bits, | 
|  | 1164 | but the offset only uses 24 bits. | 
|  | 1165 | */ | 
|  | 1166 |  | 
|  | 1167 | shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset), | 
|  | 1168 | shptr, 4); | 
|  | 1169 | shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset), | 
|  | 1170 | shptr, 4); | 
|  | 1171 | shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset), | 
|  | 1172 | shptr, 4); | 
|  | 1173 | shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), | 
|  | 1174 | shptr, 4); | 
|  | 1175 |  | 
|  | 1176 | /* This one is truly weird. What kind of weirdo decided that in | 
|  | 1177 | a system dominated by 16 and 32 bit integers, they would use | 
|  | 1178 | a just 12 bits ? | 
|  | 1179 | */ | 
|  | 1180 |  | 
|  | 1181 | shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); | 
|  | 1182 |  | 
|  | 1183 | /* Why is this nybblified, when the MSB is *always* zero ? | 
|  | 1184 | Anyway, we can't take address of bitfield, so make a | 
|  | 1185 | good-faith guess at where it starts. | 
|  | 1186 | */ | 
|  | 1187 |  | 
|  | 1188 | shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), | 
|  | 1189 | shptr, 2); | 
|  | 1190 |  | 
|  | 1191 | if (wavefront_cmd (header->size ? | 
|  | 1192 | WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, | 
|  | 1193 | NULL, sample_hdr)) { | 
|  | 1194 | printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n", | 
|  | 1195 | header->size ? "" : "header "); | 
|  | 1196 | return -(EIO); | 
|  | 1197 | } | 
|  | 1198 |  | 
|  | 1199 | if (header->size == 0) { | 
|  | 1200 | goto sent; /* Sorry. Just had to have one somewhere */ | 
|  | 1201 | } | 
|  | 1202 |  | 
|  | 1203 | data_end = dataptr + length; | 
|  | 1204 |  | 
|  | 1205 | /* Do any initial skip over an unused channel's data */ | 
|  | 1206 |  | 
|  | 1207 | dataptr += initial_skip; | 
|  | 1208 |  | 
|  | 1209 | for (written = 0, blocknum = 0; | 
|  | 1210 | written < length; written += max_blksize, blocknum++) { | 
|  | 1211 |  | 
|  | 1212 | if ((length - written) > max_blksize) { | 
|  | 1213 | blocksize = max_blksize; | 
|  | 1214 | } else { | 
|  | 1215 | /* round to nearest 16-byte value */ | 
|  | 1216 | blocksize = ((length-written+7)&~0x7); | 
|  | 1217 | } | 
|  | 1218 |  | 
|  | 1219 | if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, NULL, NULL)) { | 
|  | 1220 | printk (KERN_WARNING LOGNAME "download block " | 
|  | 1221 | "request refused.\n"); | 
|  | 1222 | return -(EIO); | 
|  | 1223 | } | 
|  | 1224 |  | 
|  | 1225 | for (i = 0; i < blocksize; i++) { | 
|  | 1226 |  | 
|  | 1227 | if (dataptr < data_end) { | 
|  | 1228 |  | 
|  | 1229 | __get_user (sample_short, dataptr); | 
|  | 1230 | dataptr += skip; | 
|  | 1231 |  | 
|  | 1232 | if (data_is_unsigned) { /* GUS ? */ | 
|  | 1233 |  | 
|  | 1234 | if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { | 
|  | 1235 |  | 
|  | 1236 | /* 8 bit sample | 
|  | 1237 | resolution, sign | 
|  | 1238 | extend both bytes. | 
|  | 1239 | */ | 
|  | 1240 |  | 
|  | 1241 | ((unsigned char*) | 
|  | 1242 | &sample_short)[0] += 0x7f; | 
|  | 1243 | ((unsigned char*) | 
|  | 1244 | &sample_short)[1] += 0x7f; | 
|  | 1245 |  | 
|  | 1246 | } else { | 
|  | 1247 |  | 
|  | 1248 | /* 16 bit sample | 
|  | 1249 | resolution, sign | 
|  | 1250 | extend the MSB. | 
|  | 1251 | */ | 
|  | 1252 |  | 
|  | 1253 | sample_short += 0x7fff; | 
|  | 1254 | } | 
|  | 1255 | } | 
|  | 1256 |  | 
|  | 1257 | } else { | 
|  | 1258 |  | 
|  | 1259 | /* In padding section of final block: | 
|  | 1260 |  | 
|  | 1261 | Don't fetch unsupplied data from | 
|  | 1262 | user space, just continue with | 
|  | 1263 | whatever the final value was. | 
|  | 1264 | */ | 
|  | 1265 | } | 
|  | 1266 |  | 
|  | 1267 | if (i < blocksize - 1) { | 
|  | 1268 | outw (sample_short, dev.block_port); | 
|  | 1269 | } else { | 
|  | 1270 | outw (sample_short, dev.last_block_port); | 
|  | 1271 | } | 
|  | 1272 | } | 
|  | 1273 |  | 
|  | 1274 | /* Get "DMA page acknowledge", even though its really | 
|  | 1275 | nothing to do with DMA at all. | 
|  | 1276 | */ | 
|  | 1277 |  | 
|  | 1278 | if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) { | 
|  | 1279 | if (dma_ack == -1) { | 
|  | 1280 | printk (KERN_ERR LOGNAME "upload sample " | 
|  | 1281 | "DMA ack timeout\n"); | 
|  | 1282 | return -(EIO); | 
|  | 1283 | } else { | 
|  | 1284 | printk (KERN_ERR LOGNAME "upload sample " | 
|  | 1285 | "DMA ack error 0x%x\n", | 
|  | 1286 | dma_ack); | 
|  | 1287 | return -(EIO); | 
|  | 1288 | } | 
|  | 1289 | } | 
|  | 1290 | } | 
|  | 1291 |  | 
|  | 1292 | dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE); | 
|  | 1293 |  | 
|  | 1294 | /* Note, label is here because sending the sample header shouldn't | 
|  | 1295 | alter the sample_status info at all. | 
|  | 1296 | */ | 
|  | 1297 |  | 
|  | 1298 | sent: | 
|  | 1299 | return (0); | 
|  | 1300 | } | 
|  | 1301 |  | 
|  | 1302 | static int | 
|  | 1303 | wavefront_send_alias (wavefront_patch_info *header) | 
|  | 1304 |  | 
|  | 1305 | { | 
|  | 1306 | unsigned char alias_hdr[WF_ALIAS_BYTES]; | 
|  | 1307 |  | 
|  | 1308 | DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is " | 
|  | 1309 | "alias for %d\n", | 
|  | 1310 | header->number, | 
|  | 1311 | header->hdr.a.OriginalSample); | 
|  | 1312 |  | 
|  | 1313 | munge_int32 (header->number, &alias_hdr[0], 2); | 
|  | 1314 | munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); | 
|  | 1315 | munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset), | 
|  | 1316 | &alias_hdr[4], 4); | 
|  | 1317 | munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset), | 
|  | 1318 | &alias_hdr[8], 4); | 
|  | 1319 | munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset), | 
|  | 1320 | &alias_hdr[12], 4); | 
|  | 1321 | munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset), | 
|  | 1322 | &alias_hdr[16], 4); | 
|  | 1323 | munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3); | 
|  | 1324 | munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); | 
|  | 1325 |  | 
|  | 1326 | if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { | 
|  | 1327 | printk (KERN_ERR LOGNAME "download alias failed.\n"); | 
|  | 1328 | return -(EIO); | 
|  | 1329 | } | 
|  | 1330 |  | 
|  | 1331 | dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); | 
|  | 1332 |  | 
|  | 1333 | return (0); | 
|  | 1334 | } | 
|  | 1335 |  | 
|  | 1336 | static int | 
|  | 1337 | wavefront_send_multisample (wavefront_patch_info *header) | 
|  | 1338 | { | 
|  | 1339 | int i; | 
|  | 1340 | int num_samples; | 
|  | 1341 | unsigned char msample_hdr[WF_MSAMPLE_BYTES]; | 
|  | 1342 |  | 
|  | 1343 | munge_int32 (header->number, &msample_hdr[0], 2); | 
|  | 1344 |  | 
|  | 1345 | /* You'll recall at this point that the "number of samples" value | 
|  | 1346 | in a wavefront_multisample struct is actually the log2 of the | 
|  | 1347 | real number of samples. | 
|  | 1348 | */ | 
|  | 1349 |  | 
|  | 1350 | num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); | 
|  | 1351 | msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; | 
|  | 1352 |  | 
|  | 1353 | DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n", | 
|  | 1354 | header->number, | 
|  | 1355 | header->hdr.ms.NumberOfSamples, | 
|  | 1356 | num_samples); | 
|  | 1357 |  | 
|  | 1358 | for (i = 0; i < num_samples; i++) { | 
|  | 1359 | DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n", | 
|  | 1360 | i, header->hdr.ms.SampleNumber[i]); | 
|  | 1361 | munge_int32 (header->hdr.ms.SampleNumber[i], | 
|  | 1362 | &msample_hdr[3+(i*2)], 2); | 
|  | 1363 | } | 
|  | 1364 |  | 
|  | 1365 | /* Need a hack here to pass in the number of bytes | 
|  | 1366 | to be written to the synth. This is ugly, and perhaps | 
|  | 1367 | one day, I'll fix it. | 
|  | 1368 | */ | 
|  | 1369 |  | 
|  | 1370 | if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE, | 
|  | 1371 | (unsigned char *) ((num_samples*2)+3), | 
|  | 1372 | msample_hdr)) { | 
|  | 1373 | printk (KERN_ERR LOGNAME "download of multisample failed.\n"); | 
|  | 1374 | return -(EIO); | 
|  | 1375 | } | 
|  | 1376 |  | 
|  | 1377 | dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); | 
|  | 1378 |  | 
|  | 1379 | return (0); | 
|  | 1380 | } | 
|  | 1381 |  | 
|  | 1382 | static int | 
|  | 1383 | wavefront_fetch_multisample (wavefront_patch_info *header) | 
|  | 1384 | { | 
|  | 1385 | int i; | 
|  | 1386 | unsigned char log_ns[1]; | 
|  | 1387 | unsigned char number[2]; | 
|  | 1388 | int num_samples; | 
|  | 1389 |  | 
|  | 1390 | munge_int32 (header->number, number, 2); | 
|  | 1391 |  | 
|  | 1392 | if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { | 
|  | 1393 | printk (KERN_ERR LOGNAME "upload multisample failed.\n"); | 
|  | 1394 | return -(EIO); | 
|  | 1395 | } | 
|  | 1396 |  | 
|  | 1397 | DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n", | 
|  | 1398 | header->number, log_ns[0]); | 
|  | 1399 |  | 
|  | 1400 | header->hdr.ms.NumberOfSamples = log_ns[0]; | 
|  | 1401 |  | 
|  | 1402 | /* get the number of samples ... */ | 
|  | 1403 |  | 
|  | 1404 | num_samples = (1 << log_ns[0]); | 
|  | 1405 |  | 
|  | 1406 | for (i = 0; i < num_samples; i++) { | 
|  | 1407 | s8 d[2]; | 
|  | 1408 |  | 
|  | 1409 | if ((d[0] = wavefront_read ()) == -1) { | 
|  | 1410 | printk (KERN_ERR LOGNAME "upload multisample failed " | 
|  | 1411 | "during sample loop.\n"); | 
|  | 1412 | return -(EIO); | 
|  | 1413 | } | 
|  | 1414 |  | 
|  | 1415 | if ((d[1] = wavefront_read ()) == -1) { | 
|  | 1416 | printk (KERN_ERR LOGNAME "upload multisample failed " | 
|  | 1417 | "during sample loop.\n"); | 
|  | 1418 | return -(EIO); | 
|  | 1419 | } | 
|  | 1420 |  | 
|  | 1421 | header->hdr.ms.SampleNumber[i] = | 
|  | 1422 | demunge_int32 ((unsigned char *) d, 2); | 
|  | 1423 |  | 
|  | 1424 | DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n", | 
|  | 1425 | i, header->hdr.ms.SampleNumber[i]); | 
|  | 1426 | } | 
|  | 1427 |  | 
|  | 1428 | return (0); | 
|  | 1429 | } | 
|  | 1430 |  | 
|  | 1431 |  | 
|  | 1432 | static int | 
|  | 1433 | wavefront_send_drum (wavefront_patch_info *header) | 
|  | 1434 |  | 
|  | 1435 | { | 
|  | 1436 | unsigned char drumbuf[WF_DRUM_BYTES]; | 
|  | 1437 | wavefront_drum *drum = &header->hdr.d; | 
|  | 1438 | int i; | 
|  | 1439 |  | 
|  | 1440 | DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI " | 
|  | 1441 | "note %d, patch = %d\n", | 
|  | 1442 | header->number, drum->PatchNumber); | 
|  | 1443 |  | 
|  | 1444 | drumbuf[0] = header->number & 0x7f; | 
|  | 1445 |  | 
|  | 1446 | for (i = 0; i < 4; i++) { | 
|  | 1447 | munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2); | 
|  | 1448 | } | 
|  | 1449 |  | 
|  | 1450 | if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { | 
|  | 1451 | printk (KERN_ERR LOGNAME "download drum failed.\n"); | 
|  | 1452 | return -(EIO); | 
|  | 1453 | } | 
|  | 1454 |  | 
|  | 1455 | return (0); | 
|  | 1456 | } | 
|  | 1457 |  | 
|  | 1458 | static int | 
|  | 1459 | wavefront_find_free_sample (void) | 
|  | 1460 |  | 
|  | 1461 | { | 
|  | 1462 | int i; | 
|  | 1463 |  | 
|  | 1464 | for (i = 0; i < WF_MAX_SAMPLE; i++) { | 
|  | 1465 | if (!(dev.sample_status[i] & WF_SLOT_FILLED)) { | 
|  | 1466 | return i; | 
|  | 1467 | } | 
|  | 1468 | } | 
|  | 1469 | printk (KERN_WARNING LOGNAME "no free sample slots!\n"); | 
|  | 1470 | return -1; | 
|  | 1471 | } | 
|  | 1472 |  | 
|  | 1473 | static int | 
|  | 1474 | wavefront_find_free_patch (void) | 
|  | 1475 |  | 
|  | 1476 | { | 
|  | 1477 | int i; | 
|  | 1478 |  | 
|  | 1479 | for (i = 0; i < WF_MAX_PATCH; i++) { | 
|  | 1480 | if (!(dev.patch_status[i] & WF_SLOT_FILLED)) { | 
|  | 1481 | return i; | 
|  | 1482 | } | 
|  | 1483 | } | 
|  | 1484 | printk (KERN_WARNING LOGNAME "no free patch slots!\n"); | 
|  | 1485 | return -1; | 
|  | 1486 | } | 
|  | 1487 |  | 
|  | 1488 | static int | 
|  | 1489 | log2_2048(int n) | 
|  | 1490 |  | 
|  | 1491 | { | 
|  | 1492 | int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143, | 
|  | 1493 | 6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192, | 
|  | 1494 | 8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390, | 
|  | 1495 | 9510, 9626, 9738, 9845, 9949, 10049, 10146}; | 
|  | 1496 | int i; | 
|  | 1497 |  | 
|  | 1498 | /* Returns 2048*log2(n) */ | 
|  | 1499 |  | 
|  | 1500 | /* FIXME: this is like doing integer math | 
|  | 1501 | on quantum particles (RuN) */ | 
|  | 1502 |  | 
|  | 1503 | i=0; | 
|  | 1504 | while(n>=32*256) { | 
|  | 1505 | n>>=8; | 
|  | 1506 | i+=2048*8; | 
|  | 1507 | } | 
|  | 1508 | while(n>=32) { | 
|  | 1509 | n>>=1; | 
|  | 1510 | i+=2048; | 
|  | 1511 | } | 
|  | 1512 | i+=tbl[n]; | 
|  | 1513 | return(i); | 
|  | 1514 | } | 
|  | 1515 |  | 
|  | 1516 | static int | 
|  | 1517 | wavefront_load_gus_patch (int devno, int format, const char __user *addr, | 
|  | 1518 | int offs, int count, int pmgr_flag) | 
|  | 1519 | { | 
|  | 1520 | struct patch_info guspatch; | 
|  | 1521 | wavefront_patch_info *samp, *pat, *prog; | 
|  | 1522 | wavefront_patch *patp; | 
|  | 1523 | wavefront_sample *sampp; | 
|  | 1524 | wavefront_program *progp; | 
|  | 1525 |  | 
|  | 1526 | int i,base_note; | 
|  | 1527 | long sizeof_patch; | 
|  | 1528 | int rc = -ENOMEM; | 
|  | 1529 |  | 
|  | 1530 | samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL); | 
|  | 1531 | if (!samp) | 
|  | 1532 | goto free_fail; | 
|  | 1533 | pat = samp + 1; | 
|  | 1534 | prog = pat + 1; | 
|  | 1535 |  | 
|  | 1536 | /* Copy in the header of the GUS patch */ | 
|  | 1537 |  | 
|  | 1538 | sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; | 
|  | 1539 | if (copy_from_user(&((char *) &guspatch)[offs], | 
|  | 1540 | &(addr)[offs], sizeof_patch - offs)) { | 
|  | 1541 | rc = -EFAULT; | 
|  | 1542 | goto free_fail; | 
|  | 1543 | } | 
|  | 1544 |  | 
|  | 1545 | if ((i = wavefront_find_free_patch ()) == -1) { | 
|  | 1546 | rc = -EBUSY; | 
|  | 1547 | goto free_fail; | 
|  | 1548 | } | 
|  | 1549 | pat->number = i; | 
|  | 1550 | pat->subkey = WF_ST_PATCH; | 
|  | 1551 | patp = &pat->hdr.p; | 
|  | 1552 |  | 
|  | 1553 | if ((i = wavefront_find_free_sample ()) == -1) { | 
|  | 1554 | rc = -EBUSY; | 
|  | 1555 | goto free_fail; | 
|  | 1556 | } | 
|  | 1557 | samp->number = i; | 
|  | 1558 | samp->subkey = WF_ST_SAMPLE; | 
|  | 1559 | samp->size = guspatch.len; | 
|  | 1560 | sampp = &samp->hdr.s; | 
|  | 1561 |  | 
|  | 1562 | prog->number = guspatch.instr_no; | 
|  | 1563 | progp = &prog->hdr.pr; | 
|  | 1564 |  | 
|  | 1565 | /* Setup the patch structure */ | 
|  | 1566 |  | 
|  | 1567 | patp->amplitude_bias=guspatch.volume; | 
|  | 1568 | patp->portamento=0; | 
|  | 1569 | patp->sample_number= samp->number & 0xff; | 
|  | 1570 | patp->sample_msb= samp->number >> 8; | 
|  | 1571 | patp->pitch_bend= /*12*/ 0; | 
|  | 1572 | patp->mono=1; | 
|  | 1573 | patp->retrigger=1; | 
|  | 1574 | patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1; | 
|  | 1575 | patp->frequency_bias=0; | 
|  | 1576 | patp->restart=0; | 
|  | 1577 | patp->reuse=0; | 
|  | 1578 | patp->reset_lfo=1; | 
|  | 1579 | patp->fm_src2=0; | 
|  | 1580 | patp->fm_src1=WF_MOD_MOD_WHEEL; | 
|  | 1581 | patp->am_src=WF_MOD_PRESSURE; | 
|  | 1582 | patp->am_amount=127; | 
|  | 1583 | patp->fc1_mod_amount=0; | 
|  | 1584 | patp->fc2_mod_amount=0; | 
|  | 1585 | patp->fm_amount1=0; | 
|  | 1586 | patp->fm_amount2=0; | 
|  | 1587 | patp->envelope1.attack_level=127; | 
|  | 1588 | patp->envelope1.decay1_level=127; | 
|  | 1589 | patp->envelope1.decay2_level=127; | 
|  | 1590 | patp->envelope1.sustain_level=127; | 
|  | 1591 | patp->envelope1.release_level=0; | 
|  | 1592 | patp->envelope2.attack_velocity=127; | 
|  | 1593 | patp->envelope2.attack_level=127; | 
|  | 1594 | patp->envelope2.decay1_level=127; | 
|  | 1595 | patp->envelope2.decay2_level=127; | 
|  | 1596 | patp->envelope2.sustain_level=127; | 
|  | 1597 | patp->envelope2.release_level=0; | 
|  | 1598 | patp->envelope2.attack_velocity=127; | 
|  | 1599 | patp->randomizer=0; | 
|  | 1600 |  | 
|  | 1601 | /* Program for this patch */ | 
|  | 1602 |  | 
|  | 1603 | progp->layer[0].patch_number= pat->number; /* XXX is this right ? */ | 
|  | 1604 | progp->layer[0].mute=1; | 
|  | 1605 | progp->layer[0].pan_or_mod=1; | 
|  | 1606 | progp->layer[0].pan=7; | 
|  | 1607 | progp->layer[0].mix_level=127  /* guspatch.volume */; | 
|  | 1608 | progp->layer[0].split_type=0; | 
|  | 1609 | progp->layer[0].split_point=0; | 
|  | 1610 | progp->layer[0].play_below=0; | 
|  | 1611 |  | 
|  | 1612 | for (i = 1; i < 4; i++) { | 
|  | 1613 | progp->layer[i].mute=0; | 
|  | 1614 | } | 
|  | 1615 |  | 
|  | 1616 | /* Sample data */ | 
|  | 1617 |  | 
|  | 1618 | sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1); | 
|  | 1619 |  | 
|  | 1620 | for (base_note=0; | 
|  | 1621 | note_to_freq (base_note) < guspatch.base_note; | 
|  | 1622 | base_note++); | 
|  | 1623 |  | 
|  | 1624 | if ((guspatch.base_note-note_to_freq(base_note)) | 
|  | 1625 | >(note_to_freq(base_note)-guspatch.base_note)) | 
|  | 1626 | base_note++; | 
|  | 1627 |  | 
|  | 1628 | printk(KERN_DEBUG "ref freq=%d,base note=%d\n", | 
|  | 1629 | guspatch.base_freq, | 
|  | 1630 | base_note); | 
|  | 1631 |  | 
|  | 1632 | sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq) | 
|  | 1633 | + base_note*171); | 
|  | 1634 | printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias); | 
|  | 1635 | sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0; | 
|  | 1636 | sampp->sampleStartOffset.Fraction=0; | 
|  | 1637 | sampp->sampleStartOffset.Integer=0; | 
|  | 1638 | sampp->loopStartOffset.Fraction=0; | 
|  | 1639 | sampp->loopStartOffset.Integer=guspatch.loop_start | 
|  | 1640 | >>((guspatch.mode&WAVE_16_BITS) ? 1:0); | 
|  | 1641 | sampp->loopEndOffset.Fraction=0; | 
|  | 1642 | sampp->loopEndOffset.Integer=guspatch.loop_end | 
|  | 1643 | >>((guspatch.mode&WAVE_16_BITS) ? 1:0); | 
|  | 1644 | sampp->sampleEndOffset.Fraction=0; | 
|  | 1645 | sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1); | 
|  | 1646 | sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0; | 
|  | 1647 | sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0; | 
|  | 1648 |  | 
|  | 1649 | /* Now ship it down */ | 
|  | 1650 |  | 
|  | 1651 | wavefront_send_sample (samp, | 
|  | 1652 | (unsigned short __user *) &(addr)[sizeof_patch], | 
|  | 1653 | (guspatch.mode & WAVE_UNSIGNED) ? 1:0); | 
|  | 1654 | wavefront_send_patch (pat); | 
|  | 1655 | wavefront_send_program (prog); | 
|  | 1656 |  | 
|  | 1657 | /* Now pan as best we can ... use the slave/internal MIDI device | 
|  | 1658 | number if it exists (since it talks to the WaveFront), or the | 
|  | 1659 | master otherwise. | 
|  | 1660 | */ | 
|  | 1661 |  | 
|  | 1662 | if (dev.mididev > 0) { | 
|  | 1663 | midi_synth_controller (dev.mididev, guspatch.instr_no, 10, | 
|  | 1664 | ((guspatch.panning << 4) > 127) ? | 
|  | 1665 | 127 : (guspatch.panning << 4)); | 
|  | 1666 | } | 
|  | 1667 | rc = 0; | 
|  | 1668 |  | 
|  | 1669 | free_fail: | 
|  | 1670 | kfree(samp); | 
|  | 1671 | return rc; | 
|  | 1672 | } | 
|  | 1673 |  | 
|  | 1674 | static int | 
|  | 1675 | wavefront_load_patch (const char __user *addr) | 
|  | 1676 |  | 
|  | 1677 |  | 
|  | 1678 | { | 
|  | 1679 | wavefront_patch_info header; | 
|  | 1680 |  | 
|  | 1681 | if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) - | 
|  | 1682 | sizeof(wavefront_any))) { | 
|  | 1683 | printk (KERN_WARNING LOGNAME "bad address for load patch.\n"); | 
|  | 1684 | return -EFAULT; | 
|  | 1685 | } | 
|  | 1686 |  | 
|  | 1687 | DPRINT (WF_DEBUG_LOAD_PATCH, "download " | 
|  | 1688 | "Sample type: %d " | 
|  | 1689 | "Sample number: %d " | 
|  | 1690 | "Sample size: %d\n", | 
|  | 1691 | header.subkey, | 
|  | 1692 | header.number, | 
|  | 1693 | header.size); | 
|  | 1694 |  | 
|  | 1695 | switch (header.subkey) { | 
|  | 1696 | case WF_ST_SAMPLE:  /* sample or sample_header, based on patch->size */ | 
|  | 1697 |  | 
|  | 1698 | if (copy_from_user((unsigned char *) &header.hdr.s, | 
|  | 1699 | (unsigned char __user *) header.hdrptr, | 
|  | 1700 | sizeof (wavefront_sample))) | 
|  | 1701 | return -EFAULT; | 
|  | 1702 |  | 
|  | 1703 | return wavefront_send_sample (&header, header.dataptr, 0); | 
|  | 1704 |  | 
|  | 1705 | case WF_ST_MULTISAMPLE: | 
|  | 1706 |  | 
|  | 1707 | if (copy_from_user(&header.hdr.s, header.hdrptr, | 
|  | 1708 | sizeof(wavefront_multisample))) | 
|  | 1709 | return -EFAULT; | 
|  | 1710 |  | 
|  | 1711 | return wavefront_send_multisample (&header); | 
|  | 1712 |  | 
|  | 1713 |  | 
|  | 1714 | case WF_ST_ALIAS: | 
|  | 1715 |  | 
|  | 1716 | if (copy_from_user(&header.hdr.a, header.hdrptr, | 
|  | 1717 | sizeof (wavefront_alias))) | 
|  | 1718 | return -EFAULT; | 
|  | 1719 |  | 
|  | 1720 | return wavefront_send_alias (&header); | 
|  | 1721 |  | 
|  | 1722 | case WF_ST_DRUM: | 
|  | 1723 | if (copy_from_user(&header.hdr.d, header.hdrptr, | 
|  | 1724 | sizeof (wavefront_drum))) | 
|  | 1725 | return -EFAULT; | 
|  | 1726 |  | 
|  | 1727 | return wavefront_send_drum (&header); | 
|  | 1728 |  | 
|  | 1729 | case WF_ST_PATCH: | 
|  | 1730 | if (copy_from_user(&header.hdr.p, header.hdrptr, | 
|  | 1731 | sizeof (wavefront_patch))) | 
|  | 1732 | return -EFAULT; | 
|  | 1733 |  | 
|  | 1734 | return wavefront_send_patch (&header); | 
|  | 1735 |  | 
|  | 1736 | case WF_ST_PROGRAM: | 
|  | 1737 | if (copy_from_user(&header.hdr.pr, header.hdrptr, | 
|  | 1738 | sizeof (wavefront_program))) | 
|  | 1739 | return -EFAULT; | 
|  | 1740 |  | 
|  | 1741 | return wavefront_send_program (&header); | 
|  | 1742 |  | 
|  | 1743 | default: | 
|  | 1744 | printk (KERN_ERR LOGNAME "unknown patch type %d.\n", | 
|  | 1745 | header.subkey); | 
|  | 1746 | return -(EINVAL); | 
|  | 1747 | } | 
|  | 1748 |  | 
|  | 1749 | return 0; | 
|  | 1750 | } | 
|  | 1751 |  | 
|  | 1752 | /*********************************************************************** | 
|  | 1753 | WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces | 
|  | 1754 | ***********************************************************************/ | 
|  | 1755 |  | 
|  | 1756 | static void | 
|  | 1757 | process_sample_hdr (UCHAR8 *buf) | 
|  | 1758 |  | 
|  | 1759 | { | 
|  | 1760 | wavefront_sample s; | 
|  | 1761 | UCHAR8 *ptr; | 
|  | 1762 |  | 
|  | 1763 | ptr = buf; | 
|  | 1764 |  | 
|  | 1765 | /* The board doesn't send us an exact copy of a "wavefront_sample" | 
|  | 1766 | in response to an Upload Sample Header command. Instead, we | 
|  | 1767 | have to convert the data format back into our data structure, | 
|  | 1768 | just as in the Download Sample command, where we have to do | 
|  | 1769 | something very similar in the reverse direction. | 
|  | 1770 | */ | 
|  | 1771 |  | 
|  | 1772 | *((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; | 
|  | 1773 | *((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; | 
|  | 1774 | *((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; | 
|  | 1775 | *((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; | 
|  | 1776 | *((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; | 
|  | 1777 |  | 
|  | 1778 | s.SampleResolution = *ptr & 0x3; | 
|  | 1779 | s.Loop = *ptr & 0x8; | 
|  | 1780 | s.Bidirectional = *ptr & 0x10; | 
|  | 1781 | s.Reverse = *ptr & 0x40; | 
|  | 1782 |  | 
|  | 1783 | /* Now copy it back to where it came from */ | 
|  | 1784 |  | 
|  | 1785 | memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample)); | 
|  | 1786 | } | 
|  | 1787 |  | 
|  | 1788 | static int | 
|  | 1789 | wavefront_synth_control (int cmd, wavefront_control *wc) | 
|  | 1790 |  | 
|  | 1791 | { | 
|  | 1792 | unsigned char patchnumbuf[2]; | 
|  | 1793 | int i; | 
|  | 1794 |  | 
|  | 1795 | DPRINT (WF_DEBUG_CMD, "synth control with " | 
|  | 1796 | "cmd 0x%x\n", wc->cmd); | 
|  | 1797 |  | 
|  | 1798 | /* Pre-handling of or for various commands */ | 
|  | 1799 |  | 
|  | 1800 | switch (wc->cmd) { | 
|  | 1801 | case WFC_DISABLE_INTERRUPTS: | 
|  | 1802 | printk (KERN_INFO LOGNAME "interrupts disabled.\n"); | 
|  | 1803 | outb (0x80|0x20, dev.control_port); | 
|  | 1804 | dev.interrupts_on = 0; | 
|  | 1805 | return 0; | 
|  | 1806 |  | 
|  | 1807 | case WFC_ENABLE_INTERRUPTS: | 
|  | 1808 | printk (KERN_INFO LOGNAME "interrupts enabled.\n"); | 
|  | 1809 | outb (0x80|0x40|0x20, dev.control_port); | 
|  | 1810 | dev.interrupts_on = 1; | 
|  | 1811 | return 0; | 
|  | 1812 |  | 
|  | 1813 | case WFC_INTERRUPT_STATUS: | 
|  | 1814 | wc->rbuf[0] = dev.interrupts_on; | 
|  | 1815 | return 0; | 
|  | 1816 |  | 
|  | 1817 | case WFC_ROMSAMPLES_RDONLY: | 
|  | 1818 | dev.rom_samples_rdonly = wc->wbuf[0]; | 
|  | 1819 | wc->status = 0; | 
|  | 1820 | return 0; | 
|  | 1821 |  | 
|  | 1822 | case WFC_IDENTIFY_SLOT_TYPE: | 
|  | 1823 | i = wc->wbuf[0] | (wc->wbuf[1] << 7); | 
|  | 1824 | if (i <0 || i >= WF_MAX_SAMPLE) { | 
|  | 1825 | printk (KERN_WARNING LOGNAME "invalid slot ID %d\n", | 
|  | 1826 | i); | 
|  | 1827 | wc->status = EINVAL; | 
|  | 1828 | return 0; | 
|  | 1829 | } | 
|  | 1830 | wc->rbuf[0] = dev.sample_status[i]; | 
|  | 1831 | wc->status = 0; | 
|  | 1832 | return 0; | 
|  | 1833 |  | 
|  | 1834 | case WFC_DEBUG_DRIVER: | 
|  | 1835 | dev.debug = wc->wbuf[0]; | 
|  | 1836 | printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug); | 
|  | 1837 | return 0; | 
|  | 1838 |  | 
|  | 1839 | case WFC_FX_IOCTL: | 
|  | 1840 | wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]); | 
|  | 1841 | return 0; | 
|  | 1842 |  | 
|  | 1843 | case WFC_UPLOAD_PATCH: | 
|  | 1844 | munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2); | 
|  | 1845 | memcpy (wc->wbuf, patchnumbuf, 2); | 
|  | 1846 | break; | 
|  | 1847 |  | 
|  | 1848 | case WFC_UPLOAD_MULTISAMPLE: | 
|  | 1849 | /* multisamples have to be handled differently, and | 
|  | 1850 | cannot be dealt with properly by wavefront_cmd() alone. | 
|  | 1851 | */ | 
|  | 1852 | wc->status = wavefront_fetch_multisample | 
|  | 1853 | ((wavefront_patch_info *) wc->rbuf); | 
|  | 1854 | return 0; | 
|  | 1855 |  | 
|  | 1856 | case WFC_UPLOAD_SAMPLE_ALIAS: | 
|  | 1857 | printk (KERN_INFO LOGNAME "support for sample alias upload " | 
|  | 1858 | "being considered.\n"); | 
|  | 1859 | wc->status = EINVAL; | 
|  | 1860 | return -EINVAL; | 
|  | 1861 | } | 
|  | 1862 |  | 
|  | 1863 | wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf); | 
|  | 1864 |  | 
|  | 1865 | /* Post-handling of certain commands. | 
|  | 1866 |  | 
|  | 1867 | In particular, if the command was an upload, demunge the data | 
|  | 1868 | so that the user-level doesn't have to think about it. | 
|  | 1869 | */ | 
|  | 1870 |  | 
|  | 1871 | if (wc->status == 0) { | 
|  | 1872 | switch (wc->cmd) { | 
|  | 1873 | /* intercept any freemem requests so that we know | 
|  | 1874 | we are always current with the user-level view | 
|  | 1875 | of things. | 
|  | 1876 | */ | 
|  | 1877 |  | 
|  | 1878 | case WFC_REPORT_FREE_MEMORY: | 
|  | 1879 | dev.freemem = demunge_int32 (wc->rbuf, 4); | 
|  | 1880 | break; | 
|  | 1881 |  | 
|  | 1882 | case WFC_UPLOAD_PATCH: | 
|  | 1883 | demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); | 
|  | 1884 | break; | 
|  | 1885 |  | 
|  | 1886 | case WFC_UPLOAD_PROGRAM: | 
|  | 1887 | demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); | 
|  | 1888 | break; | 
|  | 1889 |  | 
|  | 1890 | case WFC_UPLOAD_EDRUM_PROGRAM: | 
|  | 1891 | demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); | 
|  | 1892 | break; | 
|  | 1893 |  | 
|  | 1894 | case WFC_UPLOAD_SAMPLE_HEADER: | 
|  | 1895 | process_sample_hdr (wc->rbuf); | 
|  | 1896 | break; | 
|  | 1897 |  | 
|  | 1898 | case WFC_UPLOAD_SAMPLE_ALIAS: | 
|  | 1899 | printk (KERN_INFO LOGNAME "support for " | 
|  | 1900 | "sample aliases still " | 
|  | 1901 | "being considered.\n"); | 
|  | 1902 | break; | 
|  | 1903 |  | 
|  | 1904 | case WFC_VMIDI_OFF: | 
|  | 1905 | if (virtual_midi_disable () < 0) { | 
|  | 1906 | return -(EIO); | 
|  | 1907 | } | 
|  | 1908 | break; | 
|  | 1909 |  | 
|  | 1910 | case WFC_VMIDI_ON: | 
|  | 1911 | if (virtual_midi_enable () < 0) { | 
|  | 1912 | return -(EIO); | 
|  | 1913 | } | 
|  | 1914 | break; | 
|  | 1915 | } | 
|  | 1916 | } | 
|  | 1917 |  | 
|  | 1918 | return 0; | 
|  | 1919 | } | 
|  | 1920 |  | 
|  | 1921 |  | 
|  | 1922 | /***********************************************************************/ | 
|  | 1923 | /* WaveFront: Linux file system interface (for access via raw synth)    */ | 
|  | 1924 | /***********************************************************************/ | 
|  | 1925 |  | 
|  | 1926 | static int | 
|  | 1927 | wavefront_open (struct inode *inode, struct file *file) | 
|  | 1928 | { | 
|  | 1929 | /* XXX fix me */ | 
|  | 1930 | dev.opened = file->f_flags; | 
|  | 1931 | return 0; | 
|  | 1932 | } | 
|  | 1933 |  | 
|  | 1934 | static int | 
|  | 1935 | wavefront_release(struct inode *inode, struct file *file) | 
|  | 1936 | { | 
|  | 1937 | lock_kernel(); | 
|  | 1938 | dev.opened = 0; | 
|  | 1939 | dev.debug = 0; | 
|  | 1940 | unlock_kernel(); | 
|  | 1941 | return 0; | 
|  | 1942 | } | 
|  | 1943 |  | 
|  | 1944 | static int | 
|  | 1945 | wavefront_ioctl(struct inode *inode, struct file *file, | 
|  | 1946 | unsigned int cmd, unsigned long arg) | 
|  | 1947 | { | 
|  | 1948 | wavefront_control wc; | 
|  | 1949 | int err; | 
|  | 1950 |  | 
|  | 1951 | switch (cmd) { | 
|  | 1952 |  | 
|  | 1953 | case WFCTL_WFCMD: | 
|  | 1954 | if (copy_from_user(&wc, (void __user *) arg, sizeof (wc))) | 
|  | 1955 | return -EFAULT; | 
|  | 1956 |  | 
|  | 1957 | if ((err = wavefront_synth_control (cmd, &wc)) == 0) { | 
|  | 1958 | if (copy_to_user ((void __user *) arg, &wc, sizeof (wc))) | 
|  | 1959 | return -EFAULT; | 
|  | 1960 | } | 
|  | 1961 |  | 
|  | 1962 | return err; | 
|  | 1963 |  | 
|  | 1964 | case WFCTL_LOAD_SPP: | 
|  | 1965 | return wavefront_load_patch ((const char __user *) arg); | 
|  | 1966 |  | 
|  | 1967 | default: | 
|  | 1968 | printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd); | 
|  | 1969 | return -(EINVAL); | 
|  | 1970 |  | 
|  | 1971 | } | 
|  | 1972 | return 0; | 
|  | 1973 | } | 
|  | 1974 |  | 
|  | 1975 | static /*const*/ struct file_operations wavefront_fops = { | 
|  | 1976 | .owner		= THIS_MODULE, | 
|  | 1977 | .llseek		= no_llseek, | 
|  | 1978 | .ioctl		= wavefront_ioctl, | 
|  | 1979 | .open		= wavefront_open, | 
|  | 1980 | .release	= wavefront_release, | 
|  | 1981 | }; | 
|  | 1982 |  | 
|  | 1983 |  | 
|  | 1984 | /***********************************************************************/ | 
|  | 1985 | /* WaveFront: OSS installation and support interface                   */ | 
|  | 1986 | /***********************************************************************/ | 
|  | 1987 |  | 
|  | 1988 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 1989 |  | 
|  | 1990 | static struct synth_info wavefront_info = | 
|  | 1991 | {"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT, | 
|  | 1992 | 0, 32, 0, 0, SYNTH_CAP_INPUT}; | 
|  | 1993 |  | 
|  | 1994 | static int | 
|  | 1995 | wavefront_oss_open (int devno, int mode) | 
|  | 1996 |  | 
|  | 1997 | { | 
|  | 1998 | dev.opened = mode; | 
|  | 1999 | return 0; | 
|  | 2000 | } | 
|  | 2001 |  | 
|  | 2002 | static void | 
|  | 2003 | wavefront_oss_close (int devno) | 
|  | 2004 |  | 
|  | 2005 | { | 
|  | 2006 | dev.opened = 0; | 
|  | 2007 | dev.debug = 0; | 
|  | 2008 | return; | 
|  | 2009 | } | 
|  | 2010 |  | 
|  | 2011 | static int | 
|  | 2012 | wavefront_oss_ioctl (int devno, unsigned int cmd, void __user * arg) | 
|  | 2013 |  | 
|  | 2014 | { | 
|  | 2015 | wavefront_control wc; | 
|  | 2016 | int err; | 
|  | 2017 |  | 
|  | 2018 | switch (cmd) { | 
|  | 2019 | case SNDCTL_SYNTH_INFO: | 
|  | 2020 | if(copy_to_user(arg, &wavefront_info, sizeof (wavefront_info))) | 
|  | 2021 | return -EFAULT; | 
|  | 2022 | return 0; | 
|  | 2023 |  | 
|  | 2024 | case SNDCTL_SEQ_RESETSAMPLES: | 
|  | 2025 | //		printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n"); | 
|  | 2026 | return 0; /* don't force an error */ | 
|  | 2027 |  | 
|  | 2028 | case SNDCTL_SEQ_PERCMODE: | 
|  | 2029 | return 0; /* don't force an error */ | 
|  | 2030 |  | 
|  | 2031 | case SNDCTL_SYNTH_MEMAVL: | 
|  | 2032 | if ((dev.freemem = wavefront_freemem ()) < 0) { | 
|  | 2033 | printk (KERN_ERR LOGNAME "cannot get memory size\n"); | 
|  | 2034 | return -EIO; | 
|  | 2035 | } else { | 
|  | 2036 | return dev.freemem; | 
|  | 2037 | } | 
|  | 2038 | break; | 
|  | 2039 |  | 
|  | 2040 | case SNDCTL_SYNTH_CONTROL: | 
|  | 2041 | if(copy_from_user (&wc, arg, sizeof (wc))) | 
|  | 2042 | err = -EFAULT; | 
|  | 2043 | else if ((err = wavefront_synth_control (cmd, &wc)) == 0) { | 
|  | 2044 | if(copy_to_user (arg, &wc, sizeof (wc))) | 
|  | 2045 | err = -EFAULT; | 
|  | 2046 | } | 
|  | 2047 |  | 
|  | 2048 | return err; | 
|  | 2049 |  | 
|  | 2050 | default: | 
|  | 2051 | return -(EINVAL); | 
|  | 2052 | } | 
|  | 2053 | } | 
|  | 2054 |  | 
|  | 2055 | static int | 
|  | 2056 | wavefront_oss_load_patch (int devno, int format, const char __user *addr, | 
|  | 2057 | int offs, int count, int pmgr_flag) | 
|  | 2058 | { | 
|  | 2059 |  | 
|  | 2060 | if (format == SYSEX_PATCH) {	/* Handled by midi_synth.c */ | 
|  | 2061 | if (midi_load_patch == NULL) { | 
|  | 2062 | printk (KERN_ERR LOGNAME | 
|  | 2063 | "SYSEX not loadable: " | 
|  | 2064 | "no midi patch loader!\n"); | 
|  | 2065 | return -(EINVAL); | 
|  | 2066 | } | 
|  | 2067 |  | 
|  | 2068 | return midi_load_patch (devno, format, addr, | 
|  | 2069 | offs, count, pmgr_flag); | 
|  | 2070 |  | 
|  | 2071 | } else if (format == GUS_PATCH) { | 
|  | 2072 | return wavefront_load_gus_patch (devno, format, | 
|  | 2073 | addr, offs, count, pmgr_flag); | 
|  | 2074 |  | 
|  | 2075 | } else if (format != WAVEFRONT_PATCH) { | 
|  | 2076 | printk (KERN_ERR LOGNAME "unknown patch format %d\n", format); | 
|  | 2077 | return -(EINVAL); | 
|  | 2078 | } | 
|  | 2079 |  | 
|  | 2080 | if (count < sizeof (wavefront_patch_info)) { | 
|  | 2081 | printk (KERN_ERR LOGNAME "sample header too short\n"); | 
|  | 2082 | return -(EINVAL); | 
|  | 2083 | } | 
|  | 2084 |  | 
|  | 2085 | /* "addr" points to a user-space wavefront_patch_info */ | 
|  | 2086 |  | 
|  | 2087 | return wavefront_load_patch (addr); | 
|  | 2088 | } | 
|  | 2089 |  | 
|  | 2090 | static struct synth_operations wavefront_operations = | 
|  | 2091 | { | 
|  | 2092 | .owner		= THIS_MODULE, | 
|  | 2093 | .id		= "WaveFront", | 
|  | 2094 | .info		= &wavefront_info, | 
|  | 2095 | .midi_dev	= 0, | 
|  | 2096 | .synth_type	= SYNTH_TYPE_SAMPLE, | 
|  | 2097 | .synth_subtype	= SAMPLE_TYPE_WAVEFRONT, | 
|  | 2098 | .open		= wavefront_oss_open, | 
|  | 2099 | .close		= wavefront_oss_close, | 
|  | 2100 | .ioctl		= wavefront_oss_ioctl, | 
|  | 2101 | .kill_note	= midi_synth_kill_note, | 
|  | 2102 | .start_note	= midi_synth_start_note, | 
|  | 2103 | .set_instr	= midi_synth_set_instr, | 
|  | 2104 | .reset		= midi_synth_reset, | 
|  | 2105 | .load_patch	= midi_synth_load_patch, | 
|  | 2106 | .aftertouch	= midi_synth_aftertouch, | 
|  | 2107 | .controller	= midi_synth_controller, | 
|  | 2108 | .panning	= midi_synth_panning, | 
|  | 2109 | .bender		= midi_synth_bender, | 
|  | 2110 | .setup_voice	= midi_synth_setup_voice | 
|  | 2111 | }; | 
|  | 2112 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 2113 |  | 
|  | 2114 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL | 
|  | 2115 |  | 
|  | 2116 | static void __init attach_wavefront (struct address_info *hw_config) | 
|  | 2117 | { | 
|  | 2118 | (void) install_wavefront (); | 
|  | 2119 | } | 
|  | 2120 |  | 
|  | 2121 | static int __init probe_wavefront (struct address_info *hw_config) | 
|  | 2122 | { | 
|  | 2123 | return !detect_wavefront (hw_config->irq, hw_config->io_base); | 
|  | 2124 | } | 
|  | 2125 |  | 
|  | 2126 | static void __exit unload_wavefront (struct address_info *hw_config) | 
|  | 2127 | { | 
|  | 2128 | (void) uninstall_wavefront (); | 
|  | 2129 | } | 
|  | 2130 |  | 
|  | 2131 | #endif /* OSS_SUPPORT_STATIC_INSTALL */ | 
|  | 2132 |  | 
|  | 2133 | /***********************************************************************/ | 
|  | 2134 | /* WaveFront: Linux modular sound kernel installation interface        */ | 
|  | 2135 | /***********************************************************************/ | 
|  | 2136 |  | 
|  | 2137 | static irqreturn_t | 
|  | 2138 | wavefrontintr(int irq, void *dev_id, struct pt_regs *dummy) | 
|  | 2139 | { | 
|  | 2140 | struct wf_config *hw = dev_id; | 
|  | 2141 |  | 
|  | 2142 | /* | 
|  | 2143 | Some comments on interrupts. I attempted a version of this | 
|  | 2144 | driver that used interrupts throughout the code instead of | 
|  | 2145 | doing busy and/or sleep-waiting. Alas, it appears that once | 
|  | 2146 | the Motorola firmware is downloaded, the card *never* | 
|  | 2147 | generates an RX interrupt. These are successfully generated | 
|  | 2148 | during firmware loading, and after that wavefront_status() | 
|  | 2149 | reports that an interrupt is pending on the card from time | 
|  | 2150 | to time, but it never seems to be delivered to this | 
|  | 2151 | driver. Note also that wavefront_status() continues to | 
|  | 2152 | report that RX interrupts are enabled, suggesting that I | 
|  | 2153 | didn't goof up and disable them by mistake. | 
|  | 2154 |  | 
|  | 2155 | Thus, I stepped back to a prior version of | 
|  | 2156 | wavefront_wait(), the only place where this really | 
|  | 2157 | matters. Its sad, but I've looked through the code to check | 
|  | 2158 | on things, and I really feel certain that the Motorola | 
|  | 2159 | firmware prevents RX-ready interrupts. | 
|  | 2160 | */ | 
|  | 2161 |  | 
|  | 2162 | if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { | 
|  | 2163 | return IRQ_NONE; | 
|  | 2164 | } | 
|  | 2165 |  | 
|  | 2166 | hw->irq_ok = 1; | 
|  | 2167 | hw->irq_cnt++; | 
|  | 2168 | wake_up_interruptible (&hw->interrupt_sleeper); | 
|  | 2169 | return IRQ_HANDLED; | 
|  | 2170 | } | 
|  | 2171 |  | 
|  | 2172 | /* STATUS REGISTER | 
|  | 2173 |  | 
|  | 2174 | 0 Host Rx Interrupt Enable (1=Enabled) | 
|  | 2175 | 1 Host Rx Register Full (1=Full) | 
|  | 2176 | 2 Host Rx Interrupt Pending (1=Interrupt) | 
|  | 2177 | 3 Unused | 
|  | 2178 | 4 Host Tx Interrupt (1=Enabled) | 
|  | 2179 | 5 Host Tx Register empty (1=Empty) | 
|  | 2180 | 6 Host Tx Interrupt Pending (1=Interrupt) | 
|  | 2181 | 7 Unused | 
|  | 2182 | */ | 
|  | 2183 |  | 
|  | 2184 | static int | 
|  | 2185 | wavefront_interrupt_bits (int irq) | 
|  | 2186 |  | 
|  | 2187 | { | 
|  | 2188 | int bits; | 
|  | 2189 |  | 
|  | 2190 | switch (irq) { | 
|  | 2191 | case 9: | 
|  | 2192 | bits = 0x00; | 
|  | 2193 | break; | 
|  | 2194 | case 5: | 
|  | 2195 | bits = 0x08; | 
|  | 2196 | break; | 
|  | 2197 | case 12: | 
|  | 2198 | bits = 0x10; | 
|  | 2199 | break; | 
|  | 2200 | case 15: | 
|  | 2201 | bits = 0x18; | 
|  | 2202 | break; | 
|  | 2203 |  | 
|  | 2204 | default: | 
|  | 2205 | printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq); | 
|  | 2206 | bits = -1; | 
|  | 2207 | } | 
|  | 2208 |  | 
|  | 2209 | return bits; | 
|  | 2210 | } | 
|  | 2211 |  | 
|  | 2212 | static void | 
|  | 2213 | wavefront_should_cause_interrupt (int val, int port, int timeout) | 
|  | 2214 |  | 
|  | 2215 | { | 
|  | 2216 | unsigned long flags; | 
|  | 2217 |  | 
|  | 2218 | /* this will not help on SMP - but at least it compiles */ | 
|  | 2219 | spin_lock_irqsave(&lock, flags); | 
|  | 2220 | dev.irq_ok = 0; | 
|  | 2221 | outb (val,port); | 
|  | 2222 | interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout); | 
|  | 2223 | spin_unlock_irqrestore(&lock,flags); | 
|  | 2224 | } | 
|  | 2225 |  | 
|  | 2226 | static int __init wavefront_hw_reset (void) | 
|  | 2227 | { | 
|  | 2228 | int bits; | 
|  | 2229 | int hwv[2]; | 
|  | 2230 | unsigned long irq_mask; | 
|  | 2231 | short reported_irq; | 
|  | 2232 |  | 
|  | 2233 | /* IRQ already checked in init_module() */ | 
|  | 2234 |  | 
|  | 2235 | bits = wavefront_interrupt_bits (dev.irq); | 
|  | 2236 |  | 
|  | 2237 | printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n"); | 
|  | 2238 |  | 
|  | 2239 | irq_mask = probe_irq_on (); | 
|  | 2240 |  | 
|  | 2241 | outb (0x0, dev.control_port); | 
|  | 2242 | outb (0x80 | 0x40 | bits, dev.data_port); | 
|  | 2243 | wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1, | 
|  | 2244 | dev.control_port, | 
|  | 2245 | (reset_time*HZ)/100); | 
|  | 2246 |  | 
|  | 2247 | reported_irq = probe_irq_off (irq_mask); | 
|  | 2248 |  | 
|  | 2249 | if (reported_irq != dev.irq) { | 
|  | 2250 | if (reported_irq == 0) { | 
|  | 2251 | printk (KERN_ERR LOGNAME | 
|  | 2252 | "No unassigned interrupts detected " | 
|  | 2253 | "after h/w reset\n"); | 
|  | 2254 | } else if (reported_irq < 0) { | 
|  | 2255 | printk (KERN_ERR LOGNAME | 
|  | 2256 | "Multiple unassigned interrupts detected " | 
|  | 2257 | "after h/w reset\n"); | 
|  | 2258 | } else { | 
|  | 2259 | printk (KERN_ERR LOGNAME "autodetected IRQ %d not the " | 
|  | 2260 | "value provided (%d)\n", reported_irq, | 
|  | 2261 | dev.irq); | 
|  | 2262 | } | 
|  | 2263 | dev.irq = -1; | 
|  | 2264 | return 1; | 
|  | 2265 | } else { | 
|  | 2266 | printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n", | 
|  | 2267 | reported_irq); | 
|  | 2268 | } | 
|  | 2269 |  | 
|  | 2270 | if (request_irq (dev.irq, wavefrontintr, | 
|  | 2271 | SA_INTERRUPT|SA_SHIRQ, | 
|  | 2272 | "wavefront synth", &dev) < 0) { | 
|  | 2273 | printk (KERN_WARNING LOGNAME "IRQ %d not available!\n", | 
|  | 2274 | dev.irq); | 
|  | 2275 | return 1; | 
|  | 2276 | } | 
|  | 2277 |  | 
|  | 2278 | /* try reset of port */ | 
|  | 2279 |  | 
|  | 2280 | outb (0x0, dev.control_port); | 
|  | 2281 |  | 
|  | 2282 | /* At this point, the board is in reset, and the H/W initialization | 
|  | 2283 | register is accessed at the same address as the data port. | 
|  | 2284 |  | 
|  | 2285 | Bit 7 - Enable IRQ Driver | 
|  | 2286 | 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs | 
|  | 2287 | 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. | 
|  | 2288 |  | 
|  | 2289 | Bit 6 - MIDI Interface Select | 
|  | 2290 |  | 
|  | 2291 | 0 - Use the MIDI Input from the 26-pin WaveBlaster | 
|  | 2292 | compatible header as the serial MIDI source | 
|  | 2293 | 1 - Use the MIDI Input from the 9-pin D connector as the | 
|  | 2294 | serial MIDI source. | 
|  | 2295 |  | 
|  | 2296 | Bits 5:3 - IRQ Selection | 
|  | 2297 | 0 0 0 - IRQ 2/9 | 
|  | 2298 | 0 0 1 - IRQ 5 | 
|  | 2299 | 0 1 0 - IRQ 12 | 
|  | 2300 | 0 1 1 - IRQ 15 | 
|  | 2301 | 1 0 0 - Reserved | 
|  | 2302 | 1 0 1 - Reserved | 
|  | 2303 | 1 1 0 - Reserved | 
|  | 2304 | 1 1 1 - Reserved | 
|  | 2305 |  | 
|  | 2306 | Bits 2:1 - Reserved | 
|  | 2307 | Bit 0 - Disable Boot ROM | 
|  | 2308 | 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM | 
|  | 2309 | 1 - memory accesses to 03FC30-03FFFFH are directed to external | 
|  | 2310 | storage. | 
|  | 2311 |  | 
|  | 2312 | */ | 
|  | 2313 |  | 
|  | 2314 | /* configure hardware: IRQ, enable interrupts, | 
|  | 2315 | plus external 9-pin MIDI interface selected | 
|  | 2316 | */ | 
|  | 2317 |  | 
|  | 2318 | outb (0x80 | 0x40 | bits, dev.data_port); | 
|  | 2319 |  | 
|  | 2320 | /* CONTROL REGISTER | 
|  | 2321 |  | 
|  | 2322 | 0 Host Rx Interrupt Enable (1=Enabled)      0x1 | 
|  | 2323 | 1 Unused                                    0x2 | 
|  | 2324 | 2 Unused                                    0x4 | 
|  | 2325 | 3 Unused                                    0x8 | 
|  | 2326 | 4 Host Tx Interrupt Enable                 0x10 | 
|  | 2327 | 5 Mute (0=Mute; 1=Play)                    0x20 | 
|  | 2328 | 6 Master Interrupt Enable (1=Enabled)      0x40 | 
|  | 2329 | 7 Master Reset (0=Reset; 1=Run)            0x80 | 
|  | 2330 |  | 
|  | 2331 | Take us out of reset, mute output, master + TX + RX interrupts on. | 
|  | 2332 |  | 
|  | 2333 | We'll get an interrupt presumably to tell us that the TX | 
|  | 2334 | register is clear. | 
|  | 2335 | */ | 
|  | 2336 |  | 
|  | 2337 | wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1, | 
|  | 2338 | dev.control_port, | 
|  | 2339 | (reset_time*HZ)/100); | 
|  | 2340 |  | 
|  | 2341 | /* Note: data port is now the data port, not the h/w initialization | 
|  | 2342 | port. | 
|  | 2343 | */ | 
|  | 2344 |  | 
|  | 2345 | if (!dev.irq_ok) { | 
|  | 2346 | printk (KERN_WARNING LOGNAME | 
|  | 2347 | "intr not received after h/w un-reset.\n"); | 
|  | 2348 | goto gone_bad; | 
|  | 2349 | } | 
|  | 2350 |  | 
|  | 2351 | dev.interrupts_on = 1; | 
|  | 2352 |  | 
|  | 2353 | /* Note: data port is now the data port, not the h/w initialization | 
|  | 2354 | port. | 
|  | 2355 |  | 
|  | 2356 | At this point, only "HW VERSION" or "DOWNLOAD OS" commands | 
|  | 2357 | will work. So, issue one of them, and wait for TX | 
|  | 2358 | interrupt. This can take a *long* time after a cold boot, | 
|  | 2359 | while the ISC ROM does its RAM test. The SDK says up to 4 | 
|  | 2360 | seconds - with 12MB of RAM on a Tropez+, it takes a lot | 
|  | 2361 | longer than that (~16secs). Note that the card understands | 
|  | 2362 | the difference between a warm and a cold boot, so | 
|  | 2363 | subsequent ISC2115 reboots (say, caused by module | 
|  | 2364 | reloading) will get through this much faster. | 
|  | 2365 |  | 
|  | 2366 | XXX Interesting question: why is no RX interrupt received first ? | 
|  | 2367 | */ | 
|  | 2368 |  | 
|  | 2369 | wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION, | 
|  | 2370 | dev.data_port, ramcheck_time*HZ); | 
|  | 2371 |  | 
|  | 2372 | if (!dev.irq_ok) { | 
|  | 2373 | printk (KERN_WARNING LOGNAME | 
|  | 2374 | "post-RAM-check interrupt not received.\n"); | 
|  | 2375 | goto gone_bad; | 
|  | 2376 | } | 
|  | 2377 |  | 
|  | 2378 | if (!wavefront_wait (STAT_CAN_READ)) { | 
|  | 2379 | printk (KERN_WARNING LOGNAME | 
|  | 2380 | "no response to HW version cmd.\n"); | 
|  | 2381 | goto gone_bad; | 
|  | 2382 | } | 
|  | 2383 |  | 
|  | 2384 | if ((hwv[0] = wavefront_read ()) == -1) { | 
|  | 2385 | printk (KERN_WARNING LOGNAME | 
|  | 2386 | "board not responding correctly.\n"); | 
|  | 2387 | goto gone_bad; | 
|  | 2388 | } | 
|  | 2389 |  | 
|  | 2390 | if (hwv[0] == 0xFF) { /* NAK */ | 
|  | 2391 |  | 
|  | 2392 | /* Board's RAM test failed. Try to read error code, | 
|  | 2393 | and tell us about it either way. | 
|  | 2394 | */ | 
|  | 2395 |  | 
|  | 2396 | if ((hwv[0] = wavefront_read ()) == -1) { | 
|  | 2397 | printk (KERN_WARNING LOGNAME "on-board RAM test failed " | 
|  | 2398 | "(bad error code).\n"); | 
|  | 2399 | } else { | 
|  | 2400 | printk (KERN_WARNING LOGNAME "on-board RAM test failed " | 
|  | 2401 | "(error code: 0x%x).\n", | 
|  | 2402 | hwv[0]); | 
|  | 2403 | } | 
|  | 2404 | goto gone_bad; | 
|  | 2405 | } | 
|  | 2406 |  | 
|  | 2407 | /* We're OK, just get the next byte of the HW version response */ | 
|  | 2408 |  | 
|  | 2409 | if ((hwv[1] = wavefront_read ()) == -1) { | 
|  | 2410 | printk (KERN_WARNING LOGNAME "incorrect h/w response.\n"); | 
|  | 2411 | goto gone_bad; | 
|  | 2412 | } | 
|  | 2413 |  | 
|  | 2414 | printk (KERN_INFO LOGNAME "hardware version %d.%d\n", | 
|  | 2415 | hwv[0], hwv[1]); | 
|  | 2416 |  | 
|  | 2417 | return 0; | 
|  | 2418 |  | 
|  | 2419 |  | 
|  | 2420 | gone_bad: | 
|  | 2421 | if (dev.irq >= 0) { | 
|  | 2422 | free_irq (dev.irq, &dev); | 
|  | 2423 | dev.irq = -1; | 
|  | 2424 | } | 
|  | 2425 | return (1); | 
|  | 2426 | } | 
|  | 2427 |  | 
|  | 2428 | static int __init detect_wavefront (int irq, int io_base) | 
|  | 2429 | { | 
|  | 2430 | unsigned char   rbuf[4], wbuf[4]; | 
|  | 2431 |  | 
|  | 2432 | /* TB docs say the device takes up 8 ports, but we know that | 
|  | 2433 | if there is an FX device present (i.e. a Tropez+) it really | 
|  | 2434 | consumes 16. | 
|  | 2435 | */ | 
|  | 2436 |  | 
|  | 2437 | if (check_region (io_base, 16)) { | 
|  | 2438 | printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x " | 
|  | 2439 | "already in use - ignored\n", dev.base, | 
|  | 2440 | dev.base+15); | 
|  | 2441 | return -1; | 
|  | 2442 | } | 
|  | 2443 |  | 
|  | 2444 | dev.irq = irq; | 
|  | 2445 | dev.base = io_base; | 
|  | 2446 | dev.israw = 0; | 
|  | 2447 | dev.debug = debug_default; | 
|  | 2448 | dev.interrupts_on = 0; | 
|  | 2449 | dev.irq_cnt = 0; | 
|  | 2450 | dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ | 
|  | 2451 |  | 
|  | 2452 | if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { | 
|  | 2453 |  | 
|  | 2454 | dev.fw_version[0] = rbuf[0]; | 
|  | 2455 | dev.fw_version[1] = rbuf[1]; | 
|  | 2456 | printk (KERN_INFO LOGNAME | 
|  | 2457 | "firmware %d.%d already loaded.\n", | 
|  | 2458 | rbuf[0], rbuf[1]); | 
|  | 2459 |  | 
|  | 2460 | /* check that a command actually works */ | 
|  | 2461 |  | 
|  | 2462 | if (wavefront_cmd (WFC_HARDWARE_VERSION, | 
|  | 2463 | rbuf, wbuf) == 0) { | 
|  | 2464 | dev.hw_version[0] = rbuf[0]; | 
|  | 2465 | dev.hw_version[1] = rbuf[1]; | 
|  | 2466 | } else { | 
|  | 2467 | printk (KERN_WARNING LOGNAME "not raw, but no " | 
|  | 2468 | "hardware version!\n"); | 
|  | 2469 | return 0; | 
|  | 2470 | } | 
|  | 2471 |  | 
|  | 2472 | if (!wf_raw) { | 
|  | 2473 | return 1; | 
|  | 2474 | } else { | 
|  | 2475 | printk (KERN_INFO LOGNAME | 
|  | 2476 | "reloading firmware anyway.\n"); | 
|  | 2477 | dev.israw = 1; | 
|  | 2478 | } | 
|  | 2479 |  | 
|  | 2480 | } else { | 
|  | 2481 |  | 
|  | 2482 | dev.israw = 1; | 
|  | 2483 | printk (KERN_INFO LOGNAME | 
|  | 2484 | "no response to firmware probe, assume raw.\n"); | 
|  | 2485 |  | 
|  | 2486 | } | 
|  | 2487 |  | 
|  | 2488 | init_waitqueue_head (&dev.interrupt_sleeper); | 
|  | 2489 |  | 
|  | 2490 | if (wavefront_hw_reset ()) { | 
|  | 2491 | printk (KERN_WARNING LOGNAME "hardware reset failed\n"); | 
|  | 2492 | return 0; | 
|  | 2493 | } | 
|  | 2494 |  | 
|  | 2495 | /* Check for FX device, present only on Tropez+ */ | 
|  | 2496 |  | 
|  | 2497 | dev.has_fx = (detect_wffx () == 0); | 
|  | 2498 |  | 
|  | 2499 | return 1; | 
|  | 2500 | } | 
|  | 2501 |  | 
|  | 2502 | #include "os.h" | 
|  | 2503 | #include <linux/fs.h> | 
|  | 2504 | #include <linux/mm.h> | 
|  | 2505 | #include <linux/slab.h> | 
|  | 2506 | #include <asm/uaccess.h> | 
|  | 2507 |  | 
|  | 2508 |  | 
|  | 2509 | static int | 
|  | 2510 | wavefront_download_firmware (char *path) | 
|  | 2511 |  | 
|  | 2512 | { | 
|  | 2513 | unsigned char section[WF_SECTION_MAX]; | 
|  | 2514 | char section_length; /* yes, just a char; max value is WF_SECTION_MAX */ | 
|  | 2515 | int section_cnt_downloaded = 0; | 
|  | 2516 | int fd; | 
|  | 2517 | int c; | 
|  | 2518 | int i; | 
|  | 2519 | mm_segment_t fs; | 
|  | 2520 |  | 
|  | 2521 | /* This tries to be a bit cleverer than the stuff Alan Cox did for | 
|  | 2522 | the generic sound firmware, in that it actually knows | 
|  | 2523 | something about the structure of the Motorola firmware. In | 
|  | 2524 | particular, it uses a version that has been stripped of the | 
|  | 2525 | 20K of useless header information, and had section lengths | 
|  | 2526 | added, making it possible to load the entire OS without any | 
|  | 2527 | [kv]malloc() activity, since the longest entity we ever read is | 
|  | 2528 | 42 bytes (well, WF_SECTION_MAX) long. | 
|  | 2529 | */ | 
|  | 2530 |  | 
|  | 2531 | fs = get_fs(); | 
|  | 2532 | set_fs (get_ds()); | 
|  | 2533 |  | 
|  | 2534 | if ((fd = sys_open (path, 0, 0)) < 0) { | 
|  | 2535 | printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n", | 
|  | 2536 | path); | 
|  | 2537 | return 1; | 
|  | 2538 | } | 
|  | 2539 |  | 
|  | 2540 | while (1) { | 
|  | 2541 | int x; | 
|  | 2542 |  | 
|  | 2543 | if ((x = sys_read (fd, §ion_length, sizeof (section_length))) != | 
|  | 2544 | sizeof (section_length)) { | 
|  | 2545 | printk (KERN_ERR LOGNAME "firmware read error.\n"); | 
|  | 2546 | goto failure; | 
|  | 2547 | } | 
|  | 2548 |  | 
|  | 2549 | if (section_length == 0) { | 
|  | 2550 | break; | 
|  | 2551 | } | 
|  | 2552 |  | 
|  | 2553 | if (sys_read (fd, section, section_length) != section_length) { | 
|  | 2554 | printk (KERN_ERR LOGNAME "firmware section " | 
|  | 2555 | "read error.\n"); | 
|  | 2556 | goto failure; | 
|  | 2557 | } | 
|  | 2558 |  | 
|  | 2559 | /* Send command */ | 
|  | 2560 |  | 
|  | 2561 | if (wavefront_write (WFC_DOWNLOAD_OS)) { | 
|  | 2562 | goto failure; | 
|  | 2563 | } | 
|  | 2564 |  | 
|  | 2565 | for (i = 0; i < section_length; i++) { | 
|  | 2566 | if (wavefront_write (section[i])) { | 
|  | 2567 | goto failure; | 
|  | 2568 | } | 
|  | 2569 | } | 
|  | 2570 |  | 
|  | 2571 | /* get ACK */ | 
|  | 2572 |  | 
|  | 2573 | if (wavefront_wait (STAT_CAN_READ)) { | 
|  | 2574 |  | 
|  | 2575 | if ((c = inb (dev.data_port)) != WF_ACK) { | 
|  | 2576 |  | 
|  | 2577 | printk (KERN_ERR LOGNAME "download " | 
|  | 2578 | "of section #%d not " | 
|  | 2579 | "acknowledged, ack = 0x%x\n", | 
|  | 2580 | section_cnt_downloaded + 1, c); | 
|  | 2581 | goto failure; | 
|  | 2582 |  | 
|  | 2583 | } | 
|  | 2584 |  | 
|  | 2585 | } else { | 
|  | 2586 | printk (KERN_ERR LOGNAME "time out for firmware ACK.\n"); | 
|  | 2587 | goto failure; | 
|  | 2588 | } | 
|  | 2589 |  | 
|  | 2590 | } | 
|  | 2591 |  | 
|  | 2592 | sys_close (fd); | 
|  | 2593 | set_fs (fs); | 
|  | 2594 | return 0; | 
|  | 2595 |  | 
|  | 2596 | failure: | 
|  | 2597 | sys_close (fd); | 
|  | 2598 | set_fs (fs); | 
|  | 2599 | printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n"); | 
|  | 2600 | return 1; | 
|  | 2601 | } | 
|  | 2602 |  | 
|  | 2603 | static int __init wavefront_config_midi (void) | 
|  | 2604 | { | 
|  | 2605 | unsigned char rbuf[4], wbuf[4]; | 
|  | 2606 |  | 
|  | 2607 | if (detect_wf_mpu (dev.irq, dev.base) < 0) { | 
|  | 2608 | printk (KERN_WARNING LOGNAME | 
|  | 2609 | "could not find working MIDI device\n"); | 
|  | 2610 | return -1; | 
|  | 2611 | } | 
|  | 2612 |  | 
|  | 2613 | if ((dev.mididev = install_wf_mpu ()) < 0) { | 
|  | 2614 | printk (KERN_WARNING LOGNAME | 
|  | 2615 | "MIDI interfaces not configured\n"); | 
|  | 2616 | return -1; | 
|  | 2617 | } | 
|  | 2618 |  | 
|  | 2619 | /* Route external MIDI to WaveFront synth (by default) */ | 
|  | 2620 |  | 
|  | 2621 | if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) { | 
|  | 2622 | printk (KERN_WARNING LOGNAME | 
|  | 2623 | "cannot enable MIDI-IN to synth routing.\n"); | 
|  | 2624 | /* XXX error ? */ | 
|  | 2625 | } | 
|  | 2626 |  | 
|  | 2627 |  | 
|  | 2628 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 2629 | /* Get the regular MIDI patch loading function, so we can | 
|  | 2630 | use it if we ever get handed a SYSEX patch. This is | 
|  | 2631 | unlikely, because its so damn slow, but we may as well | 
|  | 2632 | leave this functionality from maui.c behind, since it | 
|  | 2633 | could be useful for sequencer applications that can | 
|  | 2634 | only use MIDI to do patch loading. | 
|  | 2635 | */ | 
|  | 2636 |  | 
|  | 2637 | if (midi_devs[dev.mididev]->converter != NULL) { | 
|  | 2638 | midi_load_patch = midi_devs[dev.mididev]->converter->load_patch; | 
|  | 2639 | midi_devs[dev.mididev]->converter->load_patch = | 
|  | 2640 | &wavefront_oss_load_patch; | 
|  | 2641 | } | 
|  | 2642 |  | 
|  | 2643 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 2644 |  | 
|  | 2645 | /* Turn on Virtual MIDI, but first *always* turn it off, | 
|  | 2646 | since otherwise consectutive reloads of the driver will | 
|  | 2647 | never cause the hardware to generate the initial "internal" or | 
|  | 2648 | "external" source bytes in the MIDI data stream. This | 
|  | 2649 | is pretty important, since the internal hardware generally will | 
|  | 2650 | be used to generate none or very little MIDI output, and | 
|  | 2651 | thus the only source of MIDI data is actually external. Without | 
|  | 2652 | the switch bytes, the driver will think it all comes from | 
|  | 2653 | the internal interface. Duh. | 
|  | 2654 | */ | 
|  | 2655 |  | 
|  | 2656 | if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) { | 
|  | 2657 | printk (KERN_WARNING LOGNAME | 
|  | 2658 | "virtual MIDI mode not disabled\n"); | 
|  | 2659 | return 0; /* We're OK, but missing the external MIDI dev */ | 
|  | 2660 | } | 
|  | 2661 |  | 
|  | 2662 | if ((dev.ext_mididev = virtual_midi_enable ()) < 0) { | 
|  | 2663 | printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n"); | 
|  | 2664 | } else { | 
|  | 2665 | if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) { | 
|  | 2666 | printk (KERN_WARNING LOGNAME | 
|  | 2667 | "cannot enable virtual MIDI mode.\n"); | 
|  | 2668 | virtual_midi_disable (); | 
|  | 2669 | } | 
|  | 2670 | } | 
|  | 2671 |  | 
|  | 2672 | return 0; | 
|  | 2673 | } | 
|  | 2674 |  | 
|  | 2675 | static int __init wavefront_do_reset (int atboot) | 
|  | 2676 | { | 
|  | 2677 | char voices[1]; | 
|  | 2678 |  | 
|  | 2679 | if (!atboot && wavefront_hw_reset ()) { | 
|  | 2680 | printk (KERN_WARNING LOGNAME "hw reset failed.\n"); | 
|  | 2681 | goto gone_bad; | 
|  | 2682 | } | 
|  | 2683 |  | 
|  | 2684 | if (dev.israw) { | 
|  | 2685 | if (wavefront_download_firmware (ospath)) { | 
|  | 2686 | goto gone_bad; | 
|  | 2687 | } | 
|  | 2688 |  | 
|  | 2689 | dev.israw = 0; | 
|  | 2690 |  | 
|  | 2691 | /* Wait for the OS to get running. The protocol for | 
|  | 2692 | this is non-obvious, and was determined by | 
|  | 2693 | using port-IO tracing in DOSemu and some | 
|  | 2694 | experimentation here. | 
|  | 2695 |  | 
|  | 2696 | Rather than using timed waits, use interrupts creatively. | 
|  | 2697 | */ | 
|  | 2698 |  | 
|  | 2699 | wavefront_should_cause_interrupt (WFC_NOOP, | 
|  | 2700 | dev.data_port, | 
|  | 2701 | (osrun_time*HZ)); | 
|  | 2702 |  | 
|  | 2703 | if (!dev.irq_ok) { | 
|  | 2704 | printk (KERN_WARNING LOGNAME | 
|  | 2705 | "no post-OS interrupt.\n"); | 
|  | 2706 | goto gone_bad; | 
|  | 2707 | } | 
|  | 2708 |  | 
|  | 2709 | /* Now, do it again ! */ | 
|  | 2710 |  | 
|  | 2711 | wavefront_should_cause_interrupt (WFC_NOOP, | 
|  | 2712 | dev.data_port, (10*HZ)); | 
|  | 2713 |  | 
|  | 2714 | if (!dev.irq_ok) { | 
|  | 2715 | printk (KERN_WARNING LOGNAME | 
|  | 2716 | "no post-OS interrupt(2).\n"); | 
|  | 2717 | goto gone_bad; | 
|  | 2718 | } | 
|  | 2719 |  | 
|  | 2720 | /* OK, no (RX/TX) interrupts any more, but leave mute | 
|  | 2721 | in effect. | 
|  | 2722 | */ | 
|  | 2723 |  | 
|  | 2724 | outb (0x80|0x40, dev.control_port); | 
|  | 2725 |  | 
|  | 2726 | /* No need for the IRQ anymore */ | 
|  | 2727 |  | 
|  | 2728 | free_irq (dev.irq, &dev); | 
|  | 2729 |  | 
|  | 2730 | } | 
|  | 2731 |  | 
|  | 2732 | if (dev.has_fx && fx_raw) { | 
|  | 2733 | wffx_init (); | 
|  | 2734 | } | 
|  | 2735 |  | 
|  | 2736 | /* SETUPSND.EXE asks for sample memory config here, but since i | 
|  | 2737 | have no idea how to interpret the result, we'll forget | 
|  | 2738 | about it. | 
|  | 2739 | */ | 
|  | 2740 |  | 
|  | 2741 | if ((dev.freemem = wavefront_freemem ()) < 0) { | 
|  | 2742 | goto gone_bad; | 
|  | 2743 | } | 
|  | 2744 |  | 
|  | 2745 | printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024); | 
|  | 2746 |  | 
|  | 2747 | if (wavefront_write (0xf0) || | 
|  | 2748 | wavefront_write (1) || | 
|  | 2749 | (wavefront_read () < 0)) { | 
|  | 2750 | dev.debug = 0; | 
|  | 2751 | printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n"); | 
|  | 2752 | goto gone_bad; | 
|  | 2753 | } | 
|  | 2754 |  | 
|  | 2755 | voices[0] = 32; | 
|  | 2756 |  | 
|  | 2757 | if (wavefront_cmd (WFC_SET_NVOICES, NULL, voices)) { | 
|  | 2758 | printk (KERN_WARNING LOGNAME | 
|  | 2759 | "cannot set number of voices to 32.\n"); | 
|  | 2760 | goto gone_bad; | 
|  | 2761 | } | 
|  | 2762 |  | 
|  | 2763 |  | 
|  | 2764 | return 0; | 
|  | 2765 |  | 
|  | 2766 | gone_bad: | 
|  | 2767 | /* reset that sucker so that it doesn't bother us. */ | 
|  | 2768 |  | 
|  | 2769 | outb (0x0, dev.control_port); | 
|  | 2770 | dev.interrupts_on = 0; | 
|  | 2771 | if (dev.irq >= 0) { | 
|  | 2772 | free_irq (dev.irq, &dev); | 
|  | 2773 | } | 
|  | 2774 | return 1; | 
|  | 2775 | } | 
|  | 2776 |  | 
|  | 2777 | static int __init wavefront_init (int atboot) | 
|  | 2778 | { | 
|  | 2779 | int samples_are_from_rom; | 
|  | 2780 |  | 
|  | 2781 | if (dev.israw) { | 
|  | 2782 | samples_are_from_rom = 1; | 
|  | 2783 | } else { | 
|  | 2784 | /* XXX is this always true ? */ | 
|  | 2785 | samples_are_from_rom = 0; | 
|  | 2786 | } | 
|  | 2787 |  | 
|  | 2788 | if (dev.israw || fx_raw) { | 
|  | 2789 | if (wavefront_do_reset (atboot)) { | 
|  | 2790 | return -1; | 
|  | 2791 | } | 
|  | 2792 | } | 
|  | 2793 |  | 
|  | 2794 | wavefront_get_sample_status (samples_are_from_rom); | 
|  | 2795 | wavefront_get_program_status (); | 
|  | 2796 | wavefront_get_patch_status (); | 
|  | 2797 |  | 
|  | 2798 | /* Start normal operation: unreset, master interrupt enabled, no mute | 
|  | 2799 | */ | 
|  | 2800 |  | 
|  | 2801 | outb (0x80|0x40|0x20, dev.control_port); | 
|  | 2802 |  | 
|  | 2803 | return (0); | 
|  | 2804 | } | 
|  | 2805 |  | 
|  | 2806 | static int __init install_wavefront (void) | 
|  | 2807 |  | 
|  | 2808 | { | 
|  | 2809 | if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) { | 
|  | 2810 | printk (KERN_ERR LOGNAME "cannot register raw synth\n"); | 
|  | 2811 | return -1; | 
|  | 2812 | } | 
|  | 2813 |  | 
|  | 2814 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 2815 | if ((dev.oss_dev = sound_alloc_synthdev()) == -1) { | 
|  | 2816 | printk (KERN_ERR LOGNAME "Too many sequencers\n"); | 
|  | 2817 | return -1; | 
|  | 2818 | } else { | 
|  | 2819 | synth_devs[dev.oss_dev] = &wavefront_operations; | 
|  | 2820 | } | 
|  | 2821 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 2822 |  | 
|  | 2823 | if (wavefront_init (1) < 0) { | 
|  | 2824 | printk (KERN_WARNING LOGNAME "initialization failed.\n"); | 
|  | 2825 |  | 
|  | 2826 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 2827 | sound_unload_synthdev (dev.oss_dev); | 
|  | 2828 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 2829 |  | 
|  | 2830 | return -1; | 
|  | 2831 | } | 
|  | 2832 |  | 
|  | 2833 | request_region (dev.base+2, 6, "wavefront synth"); | 
|  | 2834 |  | 
|  | 2835 | if (dev.has_fx) { | 
|  | 2836 | request_region (dev.base+8, 8, "wavefront fx"); | 
|  | 2837 | } | 
|  | 2838 |  | 
|  | 2839 | if (wavefront_config_midi ()) { | 
|  | 2840 | printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n"); | 
|  | 2841 | } | 
|  | 2842 |  | 
|  | 2843 | return dev.oss_dev; | 
|  | 2844 | } | 
|  | 2845 |  | 
|  | 2846 | static void __exit uninstall_wavefront (void) | 
|  | 2847 | { | 
|  | 2848 | /* the first two i/o addresses are freed by the wf_mpu code */ | 
|  | 2849 | release_region (dev.base+2, 6); | 
|  | 2850 |  | 
|  | 2851 | if (dev.has_fx) { | 
|  | 2852 | release_region (dev.base+8, 8); | 
|  | 2853 | } | 
|  | 2854 |  | 
|  | 2855 | unregister_sound_synth (dev.synth_dev); | 
|  | 2856 |  | 
|  | 2857 | #if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ | 
|  | 2858 | sound_unload_synthdev (dev.oss_dev); | 
|  | 2859 | #endif /* OSS_SUPPORT_SEQ */ | 
|  | 2860 | uninstall_wf_mpu (); | 
|  | 2861 | } | 
|  | 2862 |  | 
|  | 2863 | /***********************************************************************/ | 
|  | 2864 | /*   WaveFront FX control                                              */ | 
|  | 2865 | /***********************************************************************/ | 
|  | 2866 |  | 
|  | 2867 | #include "yss225.h" | 
|  | 2868 |  | 
|  | 2869 | /* Control bits for the Load Control Register | 
|  | 2870 | */ | 
|  | 2871 |  | 
|  | 2872 | #define FX_LSB_TRANSFER 0x01    /* transfer after DSP LSB byte written */ | 
|  | 2873 | #define FX_MSB_TRANSFER 0x02    /* transfer after DSP MSB byte written */ | 
|  | 2874 | #define FX_AUTO_INCR    0x04    /* auto-increment DSP address after transfer */ | 
|  | 2875 |  | 
|  | 2876 | static int | 
|  | 2877 | wffx_idle (void) | 
|  | 2878 |  | 
|  | 2879 | { | 
|  | 2880 | int i; | 
|  | 2881 | unsigned int x = 0x80; | 
|  | 2882 |  | 
|  | 2883 | for (i = 0; i < 1000; i++) { | 
|  | 2884 | x = inb (dev.fx_status); | 
|  | 2885 | if ((x & 0x80) == 0) { | 
|  | 2886 | break; | 
|  | 2887 | } | 
|  | 2888 | } | 
|  | 2889 |  | 
|  | 2890 | if (x & 0x80) { | 
|  | 2891 | printk (KERN_ERR LOGNAME "FX device never idle.\n"); | 
|  | 2892 | return 0; | 
|  | 2893 | } | 
|  | 2894 |  | 
|  | 2895 | return (1); | 
|  | 2896 | } | 
|  | 2897 |  | 
|  | 2898 | int __init detect_wffx (void) | 
|  | 2899 | { | 
|  | 2900 | /* This is a crude check, but its the best one I have for now. | 
|  | 2901 | Certainly on the Maui and the Tropez, wffx_idle() will | 
|  | 2902 | report "never idle", which suggests that this test should | 
|  | 2903 | work OK. | 
|  | 2904 | */ | 
|  | 2905 |  | 
|  | 2906 | if (inb (dev.fx_status) & 0x80) { | 
|  | 2907 | printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n"); | 
|  | 2908 | return -1; | 
|  | 2909 | } | 
|  | 2910 |  | 
|  | 2911 | return 0; | 
|  | 2912 | } | 
|  | 2913 |  | 
|  | 2914 | void | 
|  | 2915 | wffx_mute (int onoff) | 
|  | 2916 |  | 
|  | 2917 | { | 
|  | 2918 | if (!wffx_idle()) { | 
|  | 2919 | return; | 
|  | 2920 | } | 
|  | 2921 |  | 
|  | 2922 | outb (onoff ? 0x02 : 0x00, dev.fx_op); | 
|  | 2923 | } | 
|  | 2924 |  | 
|  | 2925 | static int | 
|  | 2926 | wffx_memset (int page, | 
|  | 2927 | int addr, int cnt, unsigned short *data) | 
|  | 2928 | { | 
|  | 2929 | if (page < 0 || page > 7) { | 
|  | 2930 | printk (KERN_ERR LOGNAME "FX memset: " | 
|  | 2931 | "page must be >= 0 and <= 7\n"); | 
|  | 2932 | return -(EINVAL); | 
|  | 2933 | } | 
|  | 2934 |  | 
|  | 2935 | if (addr < 0 || addr > 0x7f) { | 
|  | 2936 | printk (KERN_ERR LOGNAME "FX memset: " | 
|  | 2937 | "addr must be >= 0 and <= 7f\n"); | 
|  | 2938 | return -(EINVAL); | 
|  | 2939 | } | 
|  | 2940 |  | 
|  | 2941 | if (cnt == 1) { | 
|  | 2942 |  | 
|  | 2943 | outb (FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 2944 | outb (page, dev.fx_dsp_page); | 
|  | 2945 | outb (addr, dev.fx_dsp_addr); | 
|  | 2946 | outb ((data[0] >> 8), dev.fx_dsp_msb); | 
|  | 2947 | outb ((data[0] & 0xff), dev.fx_dsp_lsb); | 
|  | 2948 |  | 
|  | 2949 | printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n", | 
|  | 2950 | page, addr, data[0]); | 
|  | 2951 |  | 
|  | 2952 | } else { | 
|  | 2953 | int i; | 
|  | 2954 |  | 
|  | 2955 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 2956 | outb (page, dev.fx_dsp_page); | 
|  | 2957 | outb (addr, dev.fx_dsp_addr); | 
|  | 2958 |  | 
|  | 2959 | for (i = 0; i < cnt; i++) { | 
|  | 2960 | outb ((data[i] >> 8), dev.fx_dsp_msb); | 
|  | 2961 | outb ((data[i] & 0xff), dev.fx_dsp_lsb); | 
|  | 2962 | if (!wffx_idle ()) { | 
|  | 2963 | break; | 
|  | 2964 | } | 
|  | 2965 | } | 
|  | 2966 |  | 
|  | 2967 | if (i != cnt) { | 
|  | 2968 | printk (KERN_WARNING LOGNAME | 
|  | 2969 | "FX memset " | 
|  | 2970 | "(0x%x, 0x%x, %p, %d) incomplete\n", | 
|  | 2971 | page, addr, data, cnt); | 
|  | 2972 | return -(EIO); | 
|  | 2973 | } | 
|  | 2974 | } | 
|  | 2975 |  | 
|  | 2976 | return 0; | 
|  | 2977 | } | 
|  | 2978 |  | 
|  | 2979 | static int | 
|  | 2980 | wffx_ioctl (wavefront_fx_info *r) | 
|  | 2981 |  | 
|  | 2982 | { | 
|  | 2983 | unsigned short page_data[256]; | 
|  | 2984 | unsigned short *pd; | 
|  | 2985 |  | 
|  | 2986 | switch (r->request) { | 
|  | 2987 | case WFFX_MUTE: | 
|  | 2988 | wffx_mute (r->data[0]); | 
|  | 2989 | return 0; | 
|  | 2990 |  | 
|  | 2991 | case WFFX_MEMSET: | 
|  | 2992 |  | 
|  | 2993 | if (r->data[2] <= 0) { | 
|  | 2994 | printk (KERN_ERR LOGNAME "cannot write " | 
|  | 2995 | "<= 0 bytes to FX\n"); | 
|  | 2996 | return -(EINVAL); | 
|  | 2997 | } else if (r->data[2] == 1) { | 
|  | 2998 | pd = (unsigned short *) &r->data[3]; | 
|  | 2999 | } else { | 
|  | 3000 | if (r->data[2] > sizeof (page_data)) { | 
|  | 3001 | printk (KERN_ERR LOGNAME "cannot write " | 
|  | 3002 | "> 255 bytes to FX\n"); | 
|  | 3003 | return -(EINVAL); | 
|  | 3004 | } | 
|  | 3005 | if (copy_from_user(page_data, | 
|  | 3006 | (unsigned char __user *)r->data[3], | 
|  | 3007 | r->data[2])) | 
|  | 3008 | return -EFAULT; | 
|  | 3009 | pd = page_data; | 
|  | 3010 | } | 
|  | 3011 |  | 
|  | 3012 | return wffx_memset (r->data[0], /* page */ | 
|  | 3013 | r->data[1], /* addr */ | 
|  | 3014 | r->data[2], /* cnt */ | 
|  | 3015 | pd); | 
|  | 3016 |  | 
|  | 3017 | default: | 
|  | 3018 | printk (KERN_WARNING LOGNAME | 
|  | 3019 | "FX: ioctl %d not yet supported\n", | 
|  | 3020 | r->request); | 
|  | 3021 | return -(EINVAL); | 
|  | 3022 | } | 
|  | 3023 | } | 
|  | 3024 |  | 
|  | 3025 | /* YSS225 initialization. | 
|  | 3026 |  | 
|  | 3027 | This code was developed using DOSEMU. The Turtle Beach SETUPSND | 
|  | 3028 | utility was run with I/O tracing in DOSEMU enabled, and a reconstruction | 
|  | 3029 | of the port I/O done, using the Yamaha faxback document as a guide | 
|  | 3030 | to add more logic to the code. Its really pretty weird. | 
|  | 3031 |  | 
|  | 3032 | There was an alternative approach of just dumping the whole I/O | 
|  | 3033 | sequence as a series of port/value pairs and a simple loop | 
|  | 3034 | that output it. However, I hope that eventually I'll get more | 
|  | 3035 | control over what this code does, and so I tried to stick with | 
|  | 3036 | a somewhat "algorithmic" approach. | 
|  | 3037 | */ | 
|  | 3038 |  | 
|  | 3039 | static int __init wffx_init (void) | 
|  | 3040 | { | 
|  | 3041 | int i; | 
|  | 3042 | int j; | 
|  | 3043 |  | 
|  | 3044 | /* Set all bits for all channels on the MOD unit to zero */ | 
|  | 3045 | /* XXX But why do this twice ? */ | 
|  | 3046 |  | 
|  | 3047 | for (j = 0; j < 2; j++) { | 
|  | 3048 | for (i = 0x10; i <= 0xff; i++) { | 
|  | 3049 |  | 
|  | 3050 | if (!wffx_idle ()) { | 
|  | 3051 | return (-1); | 
|  | 3052 | } | 
|  | 3053 |  | 
|  | 3054 | outb (i, dev.fx_mod_addr); | 
|  | 3055 | outb (0x0, dev.fx_mod_data); | 
|  | 3056 | } | 
|  | 3057 | } | 
|  | 3058 |  | 
|  | 3059 | if (!wffx_idle()) return (-1); | 
|  | 3060 | outb (0x02, dev.fx_op);                        /* mute on */ | 
|  | 3061 |  | 
|  | 3062 | if (!wffx_idle()) return (-1); | 
|  | 3063 | outb (0x07, dev.fx_dsp_page); | 
|  | 3064 | outb (0x44, dev.fx_dsp_addr); | 
|  | 3065 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3066 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3067 | if (!wffx_idle()) return (-1); | 
|  | 3068 | outb (0x07, dev.fx_dsp_page); | 
|  | 3069 | outb (0x42, dev.fx_dsp_addr); | 
|  | 3070 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3071 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3072 | if (!wffx_idle()) return (-1); | 
|  | 3073 | outb (0x07, dev.fx_dsp_page); | 
|  | 3074 | outb (0x43, dev.fx_dsp_addr); | 
|  | 3075 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3076 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3077 | if (!wffx_idle()) return (-1); | 
|  | 3078 | outb (0x07, dev.fx_dsp_page); | 
|  | 3079 | outb (0x7c, dev.fx_dsp_addr); | 
|  | 3080 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3081 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3082 | if (!wffx_idle()) return (-1); | 
|  | 3083 | outb (0x07, dev.fx_dsp_page); | 
|  | 3084 | outb (0x7e, dev.fx_dsp_addr); | 
|  | 3085 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3086 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3087 | if (!wffx_idle()) return (-1); | 
|  | 3088 | outb (0x07, dev.fx_dsp_page); | 
|  | 3089 | outb (0x46, dev.fx_dsp_addr); | 
|  | 3090 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3091 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3092 | if (!wffx_idle()) return (-1); | 
|  | 3093 | outb (0x07, dev.fx_dsp_page); | 
|  | 3094 | outb (0x49, dev.fx_dsp_addr); | 
|  | 3095 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3096 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3097 | if (!wffx_idle()) return (-1); | 
|  | 3098 | outb (0x07, dev.fx_dsp_page); | 
|  | 3099 | outb (0x47, dev.fx_dsp_addr); | 
|  | 3100 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3101 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3102 | if (!wffx_idle()) return (-1); | 
|  | 3103 | outb (0x07, dev.fx_dsp_page); | 
|  | 3104 | outb (0x4a, dev.fx_dsp_addr); | 
|  | 3105 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3106 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3107 |  | 
|  | 3108 | /* either because of stupidity by TB's programmers, or because it | 
|  | 3109 | actually does something, rezero the MOD page. | 
|  | 3110 | */ | 
|  | 3111 | for (i = 0x10; i <= 0xff; i++) { | 
|  | 3112 |  | 
|  | 3113 | if (!wffx_idle ()) { | 
|  | 3114 | return (-1); | 
|  | 3115 | } | 
|  | 3116 |  | 
|  | 3117 | outb (i, dev.fx_mod_addr); | 
|  | 3118 | outb (0x0, dev.fx_mod_data); | 
|  | 3119 | } | 
|  | 3120 | /* load page zero */ | 
|  | 3121 |  | 
|  | 3122 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3123 | outb (0x00, dev.fx_dsp_page); | 
|  | 3124 | outb (0x00, dev.fx_dsp_addr); | 
|  | 3125 |  | 
|  | 3126 | for (i = 0; i < sizeof (page_zero); i += 2) { | 
|  | 3127 | outb (page_zero[i], dev.fx_dsp_msb); | 
|  | 3128 | outb (page_zero[i+1], dev.fx_dsp_lsb); | 
|  | 3129 | if (!wffx_idle()) return (-1); | 
|  | 3130 | } | 
|  | 3131 |  | 
|  | 3132 | /* Now load page one */ | 
|  | 3133 |  | 
|  | 3134 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3135 | outb (0x01, dev.fx_dsp_page); | 
|  | 3136 | outb (0x00, dev.fx_dsp_addr); | 
|  | 3137 |  | 
|  | 3138 | for (i = 0; i < sizeof (page_one); i += 2) { | 
|  | 3139 | outb (page_one[i], dev.fx_dsp_msb); | 
|  | 3140 | outb (page_one[i+1], dev.fx_dsp_lsb); | 
|  | 3141 | if (!wffx_idle()) return (-1); | 
|  | 3142 | } | 
|  | 3143 |  | 
|  | 3144 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3145 | outb (0x02, dev.fx_dsp_page); | 
|  | 3146 | outb (0x00, dev.fx_dsp_addr); | 
|  | 3147 |  | 
|  | 3148 | for (i = 0; i < sizeof (page_two); i++) { | 
|  | 3149 | outb (page_two[i], dev.fx_dsp_lsb); | 
|  | 3150 | if (!wffx_idle()) return (-1); | 
|  | 3151 | } | 
|  | 3152 |  | 
|  | 3153 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3154 | outb (0x03, dev.fx_dsp_page); | 
|  | 3155 | outb (0x00, dev.fx_dsp_addr); | 
|  | 3156 |  | 
|  | 3157 | for (i = 0; i < sizeof (page_three); i++) { | 
|  | 3158 | outb (page_three[i], dev.fx_dsp_lsb); | 
|  | 3159 | if (!wffx_idle()) return (-1); | 
|  | 3160 | } | 
|  | 3161 |  | 
|  | 3162 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3163 | outb (0x04, dev.fx_dsp_page); | 
|  | 3164 | outb (0x00, dev.fx_dsp_addr); | 
|  | 3165 |  | 
|  | 3166 | for (i = 0; i < sizeof (page_four); i++) { | 
|  | 3167 | outb (page_four[i], dev.fx_dsp_lsb); | 
|  | 3168 | if (!wffx_idle()) return (-1); | 
|  | 3169 | } | 
|  | 3170 |  | 
|  | 3171 | /* Load memory area (page six) */ | 
|  | 3172 |  | 
|  | 3173 | outb (FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3174 | outb (0x06, dev.fx_dsp_page); | 
|  | 3175 |  | 
|  | 3176 | for (i = 0; i < sizeof (page_six); i += 3) { | 
|  | 3177 | outb (page_six[i], dev.fx_dsp_addr); | 
|  | 3178 | outb (page_six[i+1], dev.fx_dsp_msb); | 
|  | 3179 | outb (page_six[i+2], dev.fx_dsp_lsb); | 
|  | 3180 | if (!wffx_idle()) return (-1); | 
|  | 3181 | } | 
|  | 3182 |  | 
|  | 3183 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3184 | outb (0x07, dev.fx_dsp_page); | 
|  | 3185 | outb (0x00, dev.fx_dsp_addr); | 
|  | 3186 |  | 
|  | 3187 | for (i = 0; i < sizeof (page_seven); i += 2) { | 
|  | 3188 | outb (page_seven[i], dev.fx_dsp_msb); | 
|  | 3189 | outb (page_seven[i+1], dev.fx_dsp_lsb); | 
|  | 3190 | if (!wffx_idle()) return (-1); | 
|  | 3191 | } | 
|  | 3192 |  | 
|  | 3193 | /* Now setup the MOD area. We do this algorithmically in order to | 
|  | 3194 | save a little data space. It could be done in the same fashion | 
|  | 3195 | as the "pages". | 
|  | 3196 | */ | 
|  | 3197 |  | 
|  | 3198 | for (i = 0x00; i <= 0x0f; i++) { | 
|  | 3199 | outb (0x01, dev.fx_mod_addr); | 
|  | 3200 | outb (i, dev.fx_mod_data); | 
|  | 3201 | if (!wffx_idle()) return (-1); | 
|  | 3202 | outb (0x02, dev.fx_mod_addr); | 
|  | 3203 | outb (0x00, dev.fx_mod_data); | 
|  | 3204 | if (!wffx_idle()) return (-1); | 
|  | 3205 | } | 
|  | 3206 |  | 
|  | 3207 | for (i = 0xb0; i <= 0xbf; i++) { | 
|  | 3208 | outb (i, dev.fx_mod_addr); | 
|  | 3209 | outb (0x20, dev.fx_mod_data); | 
|  | 3210 | if (!wffx_idle()) return (-1); | 
|  | 3211 | } | 
|  | 3212 |  | 
|  | 3213 | for (i = 0xf0; i <= 0xff; i++) { | 
|  | 3214 | outb (i, dev.fx_mod_addr); | 
|  | 3215 | outb (0x20, dev.fx_mod_data); | 
|  | 3216 | if (!wffx_idle()) return (-1); | 
|  | 3217 | } | 
|  | 3218 |  | 
|  | 3219 | for (i = 0x10; i <= 0x1d; i++) { | 
|  | 3220 | outb (i, dev.fx_mod_addr); | 
|  | 3221 | outb (0xff, dev.fx_mod_data); | 
|  | 3222 | if (!wffx_idle()) return (-1); | 
|  | 3223 | } | 
|  | 3224 |  | 
|  | 3225 | outb (0x1e, dev.fx_mod_addr); | 
|  | 3226 | outb (0x40, dev.fx_mod_data); | 
|  | 3227 | if (!wffx_idle()) return (-1); | 
|  | 3228 |  | 
|  | 3229 | for (i = 0x1f; i <= 0x2d; i++) { | 
|  | 3230 | outb (i, dev.fx_mod_addr); | 
|  | 3231 | outb (0xff, dev.fx_mod_data); | 
|  | 3232 | if (!wffx_idle()) return (-1); | 
|  | 3233 | } | 
|  | 3234 |  | 
|  | 3235 | outb (0x2e, dev.fx_mod_addr); | 
|  | 3236 | outb (0x00, dev.fx_mod_data); | 
|  | 3237 | if (!wffx_idle()) return (-1); | 
|  | 3238 |  | 
|  | 3239 | for (i = 0x2f; i <= 0x3e; i++) { | 
|  | 3240 | outb (i, dev.fx_mod_addr); | 
|  | 3241 | outb (0x00, dev.fx_mod_data); | 
|  | 3242 | if (!wffx_idle()) return (-1); | 
|  | 3243 | } | 
|  | 3244 |  | 
|  | 3245 | outb (0x3f, dev.fx_mod_addr); | 
|  | 3246 | outb (0x20, dev.fx_mod_data); | 
|  | 3247 | if (!wffx_idle()) return (-1); | 
|  | 3248 |  | 
|  | 3249 | for (i = 0x40; i <= 0x4d; i++) { | 
|  | 3250 | outb (i, dev.fx_mod_addr); | 
|  | 3251 | outb (0x00, dev.fx_mod_data); | 
|  | 3252 | if (!wffx_idle()) return (-1); | 
|  | 3253 | } | 
|  | 3254 |  | 
|  | 3255 | outb (0x4e, dev.fx_mod_addr); | 
|  | 3256 | outb (0x0e, dev.fx_mod_data); | 
|  | 3257 | if (!wffx_idle()) return (-1); | 
|  | 3258 | outb (0x4f, dev.fx_mod_addr); | 
|  | 3259 | outb (0x0e, dev.fx_mod_data); | 
|  | 3260 | if (!wffx_idle()) return (-1); | 
|  | 3261 |  | 
|  | 3262 |  | 
|  | 3263 | for (i = 0x50; i <= 0x6b; i++) { | 
|  | 3264 | outb (i, dev.fx_mod_addr); | 
|  | 3265 | outb (0x00, dev.fx_mod_data); | 
|  | 3266 | if (!wffx_idle()) return (-1); | 
|  | 3267 | } | 
|  | 3268 |  | 
|  | 3269 | outb (0x6c, dev.fx_mod_addr); | 
|  | 3270 | outb (0x40, dev.fx_mod_data); | 
|  | 3271 | if (!wffx_idle()) return (-1); | 
|  | 3272 |  | 
|  | 3273 | outb (0x6d, dev.fx_mod_addr); | 
|  | 3274 | outb (0x00, dev.fx_mod_data); | 
|  | 3275 | if (!wffx_idle()) return (-1); | 
|  | 3276 |  | 
|  | 3277 | outb (0x6e, dev.fx_mod_addr); | 
|  | 3278 | outb (0x40, dev.fx_mod_data); | 
|  | 3279 | if (!wffx_idle()) return (-1); | 
|  | 3280 |  | 
|  | 3281 | outb (0x6f, dev.fx_mod_addr); | 
|  | 3282 | outb (0x40, dev.fx_mod_data); | 
|  | 3283 | if (!wffx_idle()) return (-1); | 
|  | 3284 |  | 
|  | 3285 | for (i = 0x70; i <= 0x7f; i++) { | 
|  | 3286 | outb (i, dev.fx_mod_addr); | 
|  | 3287 | outb (0xc0, dev.fx_mod_data); | 
|  | 3288 | if (!wffx_idle()) return (-1); | 
|  | 3289 | } | 
|  | 3290 |  | 
|  | 3291 | for (i = 0x80; i <= 0xaf; i++) { | 
|  | 3292 | outb (i, dev.fx_mod_addr); | 
|  | 3293 | outb (0x00, dev.fx_mod_data); | 
|  | 3294 | if (!wffx_idle()) return (-1); | 
|  | 3295 | } | 
|  | 3296 |  | 
|  | 3297 | for (i = 0xc0; i <= 0xdd; i++) { | 
|  | 3298 | outb (i, dev.fx_mod_addr); | 
|  | 3299 | outb (0x00, dev.fx_mod_data); | 
|  | 3300 | if (!wffx_idle()) return (-1); | 
|  | 3301 | } | 
|  | 3302 |  | 
|  | 3303 | outb (0xde, dev.fx_mod_addr); | 
|  | 3304 | outb (0x10, dev.fx_mod_data); | 
|  | 3305 | if (!wffx_idle()) return (-1); | 
|  | 3306 | outb (0xdf, dev.fx_mod_addr); | 
|  | 3307 | outb (0x10, dev.fx_mod_data); | 
|  | 3308 | if (!wffx_idle()) return (-1); | 
|  | 3309 |  | 
|  | 3310 | for (i = 0xe0; i <= 0xef; i++) { | 
|  | 3311 | outb (i, dev.fx_mod_addr); | 
|  | 3312 | outb (0x00, dev.fx_mod_data); | 
|  | 3313 | if (!wffx_idle()) return (-1); | 
|  | 3314 | } | 
|  | 3315 |  | 
|  | 3316 | for (i = 0x00; i <= 0x0f; i++) { | 
|  | 3317 | outb (0x01, dev.fx_mod_addr); | 
|  | 3318 | outb (i, dev.fx_mod_data); | 
|  | 3319 | outb (0x02, dev.fx_mod_addr); | 
|  | 3320 | outb (0x01, dev.fx_mod_data); | 
|  | 3321 | if (!wffx_idle()) return (-1); | 
|  | 3322 | } | 
|  | 3323 |  | 
|  | 3324 | outb (0x02, dev.fx_op); /* mute on */ | 
|  | 3325 |  | 
|  | 3326 | /* Now set the coefficients and so forth for the programs above */ | 
|  | 3327 |  | 
|  | 3328 | for (i = 0; i < sizeof (coefficients); i += 4) { | 
|  | 3329 | outb (coefficients[i], dev.fx_dsp_page); | 
|  | 3330 | outb (coefficients[i+1], dev.fx_dsp_addr); | 
|  | 3331 | outb (coefficients[i+2], dev.fx_dsp_msb); | 
|  | 3332 | outb (coefficients[i+3], dev.fx_dsp_lsb); | 
|  | 3333 | if (!wffx_idle()) return (-1); | 
|  | 3334 | } | 
|  | 3335 |  | 
|  | 3336 | /* Some settings (?) that are too small to bundle into loops */ | 
|  | 3337 |  | 
|  | 3338 | if (!wffx_idle()) return (-1); | 
|  | 3339 | outb (0x1e, dev.fx_mod_addr); | 
|  | 3340 | outb (0x14, dev.fx_mod_data); | 
|  | 3341 | if (!wffx_idle()) return (-1); | 
|  | 3342 | outb (0xde, dev.fx_mod_addr); | 
|  | 3343 | outb (0x20, dev.fx_mod_data); | 
|  | 3344 | if (!wffx_idle()) return (-1); | 
|  | 3345 | outb (0xdf, dev.fx_mod_addr); | 
|  | 3346 | outb (0x20, dev.fx_mod_data); | 
|  | 3347 |  | 
|  | 3348 | /* some more coefficients */ | 
|  | 3349 |  | 
|  | 3350 | if (!wffx_idle()) return (-1); | 
|  | 3351 | outb (0x06, dev.fx_dsp_page); | 
|  | 3352 | outb (0x78, dev.fx_dsp_addr); | 
|  | 3353 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3354 | outb (0x40, dev.fx_dsp_lsb); | 
|  | 3355 | if (!wffx_idle()) return (-1); | 
|  | 3356 | outb (0x07, dev.fx_dsp_page); | 
|  | 3357 | outb (0x03, dev.fx_dsp_addr); | 
|  | 3358 | outb (0x0f, dev.fx_dsp_msb); | 
|  | 3359 | outb (0xff, dev.fx_dsp_lsb); | 
|  | 3360 | if (!wffx_idle()) return (-1); | 
|  | 3361 | outb (0x07, dev.fx_dsp_page); | 
|  | 3362 | outb (0x0b, dev.fx_dsp_addr); | 
|  | 3363 | outb (0x0f, dev.fx_dsp_msb); | 
|  | 3364 | outb (0xff, dev.fx_dsp_lsb); | 
|  | 3365 | if (!wffx_idle()) return (-1); | 
|  | 3366 | outb (0x07, dev.fx_dsp_page); | 
|  | 3367 | outb (0x02, dev.fx_dsp_addr); | 
|  | 3368 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3369 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3370 | if (!wffx_idle()) return (-1); | 
|  | 3371 | outb (0x07, dev.fx_dsp_page); | 
|  | 3372 | outb (0x0a, dev.fx_dsp_addr); | 
|  | 3373 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3374 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3375 | if (!wffx_idle()) return (-1); | 
|  | 3376 | outb (0x07, dev.fx_dsp_page); | 
|  | 3377 | outb (0x46, dev.fx_dsp_addr); | 
|  | 3378 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3379 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3380 | if (!wffx_idle()) return (-1); | 
|  | 3381 | outb (0x07, dev.fx_dsp_page); | 
|  | 3382 | outb (0x49, dev.fx_dsp_addr); | 
|  | 3383 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3384 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3385 |  | 
|  | 3386 | /* Now, for some strange reason, lets reload every page | 
|  | 3387 | and all the coefficients over again. I have *NO* idea | 
|  | 3388 | why this is done. I do know that no sound is produced | 
|  | 3389 | is this phase is omitted. | 
|  | 3390 | */ | 
|  | 3391 |  | 
|  | 3392 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3393 | outb (0x00, dev.fx_dsp_page); | 
|  | 3394 | outb (0x10, dev.fx_dsp_addr); | 
|  | 3395 |  | 
|  | 3396 | for (i = 0; i < sizeof (page_zero_v2); i += 2) { | 
|  | 3397 | outb (page_zero_v2[i], dev.fx_dsp_msb); | 
|  | 3398 | outb (page_zero_v2[i+1], dev.fx_dsp_lsb); | 
|  | 3399 | if (!wffx_idle()) return (-1); | 
|  | 3400 | } | 
|  | 3401 |  | 
|  | 3402 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3403 | outb (0x01, dev.fx_dsp_page); | 
|  | 3404 | outb (0x10, dev.fx_dsp_addr); | 
|  | 3405 |  | 
|  | 3406 | for (i = 0; i < sizeof (page_one_v2); i += 2) { | 
|  | 3407 | outb (page_one_v2[i], dev.fx_dsp_msb); | 
|  | 3408 | outb (page_one_v2[i+1], dev.fx_dsp_lsb); | 
|  | 3409 | if (!wffx_idle()) return (-1); | 
|  | 3410 | } | 
|  | 3411 |  | 
|  | 3412 | if (!wffx_idle()) return (-1); | 
|  | 3413 | if (!wffx_idle()) return (-1); | 
|  | 3414 |  | 
|  | 3415 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3416 | outb (0x02, dev.fx_dsp_page); | 
|  | 3417 | outb (0x10, dev.fx_dsp_addr); | 
|  | 3418 |  | 
|  | 3419 | for (i = 0; i < sizeof (page_two_v2); i++) { | 
|  | 3420 | outb (page_two_v2[i], dev.fx_dsp_lsb); | 
|  | 3421 | if (!wffx_idle()) return (-1); | 
|  | 3422 | } | 
|  | 3423 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3424 | outb (0x03, dev.fx_dsp_page); | 
|  | 3425 | outb (0x10, dev.fx_dsp_addr); | 
|  | 3426 |  | 
|  | 3427 | for (i = 0; i < sizeof (page_three_v2); i++) { | 
|  | 3428 | outb (page_three_v2[i], dev.fx_dsp_lsb); | 
|  | 3429 | if (!wffx_idle()) return (-1); | 
|  | 3430 | } | 
|  | 3431 |  | 
|  | 3432 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3433 | outb (0x04, dev.fx_dsp_page); | 
|  | 3434 | outb (0x10, dev.fx_dsp_addr); | 
|  | 3435 |  | 
|  | 3436 | for (i = 0; i < sizeof (page_four_v2); i++) { | 
|  | 3437 | outb (page_four_v2[i], dev.fx_dsp_lsb); | 
|  | 3438 | if (!wffx_idle()) return (-1); | 
|  | 3439 | } | 
|  | 3440 |  | 
|  | 3441 | outb (FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3442 | outb (0x06, dev.fx_dsp_page); | 
|  | 3443 |  | 
|  | 3444 | /* Page six v.2 is algorithmic */ | 
|  | 3445 |  | 
|  | 3446 | for (i = 0x10; i <= 0x3e; i += 2) { | 
|  | 3447 | outb (i, dev.fx_dsp_addr); | 
|  | 3448 | outb (0x00, dev.fx_dsp_msb); | 
|  | 3449 | outb (0x00, dev.fx_dsp_lsb); | 
|  | 3450 | if (!wffx_idle()) return (-1); | 
|  | 3451 | } | 
|  | 3452 |  | 
|  | 3453 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr); | 
|  | 3454 | outb (0x07, dev.fx_dsp_page); | 
|  | 3455 | outb (0x10, dev.fx_dsp_addr); | 
|  | 3456 |  | 
|  | 3457 | for (i = 0; i < sizeof (page_seven_v2); i += 2) { | 
|  | 3458 | outb (page_seven_v2[i], dev.fx_dsp_msb); | 
|  | 3459 | outb (page_seven_v2[i+1], dev.fx_dsp_lsb); | 
|  | 3460 | if (!wffx_idle()) return (-1); | 
|  | 3461 | } | 
|  | 3462 |  | 
|  | 3463 | for (i = 0x00; i < sizeof(mod_v2); i += 2) { | 
|  | 3464 | outb (mod_v2[i], dev.fx_mod_addr); | 
|  | 3465 | outb (mod_v2[i+1], dev.fx_mod_data); | 
|  | 3466 | if (!wffx_idle()) return (-1); | 
|  | 3467 | } | 
|  | 3468 |  | 
|  | 3469 | for (i = 0; i < sizeof (coefficients2); i += 4) { | 
|  | 3470 | outb (coefficients2[i], dev.fx_dsp_page); | 
|  | 3471 | outb (coefficients2[i+1], dev.fx_dsp_addr); | 
|  | 3472 | outb (coefficients2[i+2], dev.fx_dsp_msb); | 
|  | 3473 | outb (coefficients2[i+3], dev.fx_dsp_lsb); | 
|  | 3474 | if (!wffx_idle()) return (-1); | 
|  | 3475 | } | 
|  | 3476 |  | 
|  | 3477 | for (i = 0; i < sizeof (coefficients3); i += 2) { | 
|  | 3478 | int x; | 
|  | 3479 |  | 
|  | 3480 | outb (0x07, dev.fx_dsp_page); | 
|  | 3481 | x = (i % 4) ? 0x4e : 0x4c; | 
|  | 3482 | outb (x, dev.fx_dsp_addr); | 
|  | 3483 | outb (coefficients3[i], dev.fx_dsp_msb); | 
|  | 3484 | outb (coefficients3[i+1], dev.fx_dsp_lsb); | 
|  | 3485 | } | 
|  | 3486 |  | 
|  | 3487 | outb (0x00, dev.fx_op); /* mute off */ | 
|  | 3488 | if (!wffx_idle()) return (-1); | 
|  | 3489 |  | 
|  | 3490 | return (0); | 
|  | 3491 | } | 
|  | 3492 |  | 
|  | 3493 | static int io = -1; | 
|  | 3494 | static int irq = -1; | 
|  | 3495 |  | 
|  | 3496 | MODULE_AUTHOR      ("Paul Barton-Davis <pbd@op.net>"); | 
|  | 3497 | MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver"); | 
|  | 3498 | MODULE_LICENSE("GPL"); | 
|  | 3499 | module_param       (io, int, 0); | 
|  | 3500 | module_param       (irq, int, 0); | 
|  | 3501 |  | 
|  | 3502 | static int __init init_wavfront (void) | 
|  | 3503 | { | 
|  | 3504 | printk ("Turtle Beach WaveFront Driver\n" | 
|  | 3505 | "Copyright (C) by Hannu Solvainen, " | 
|  | 3506 | "Paul Barton-Davis 1993-1998.\n"); | 
|  | 3507 |  | 
|  | 3508 | /* XXX t'would be lovely to ask the CS4232 for these values, eh ? */ | 
|  | 3509 |  | 
|  | 3510 | if (io == -1 || irq == -1) { | 
|  | 3511 | printk (KERN_INFO LOGNAME "irq and io options must be set.\n"); | 
|  | 3512 | return -EINVAL; | 
|  | 3513 | } | 
|  | 3514 |  | 
|  | 3515 | if (wavefront_interrupt_bits (irq) < 0) { | 
|  | 3516 | printk (KERN_INFO LOGNAME | 
|  | 3517 | "IRQ must be 9, 5, 12 or 15 (not %d)\n", irq); | 
|  | 3518 | return -ENODEV; | 
|  | 3519 | } | 
|  | 3520 |  | 
|  | 3521 | if (detect_wavefront (irq, io) < 0) { | 
|  | 3522 | return -ENODEV; | 
|  | 3523 | } | 
|  | 3524 |  | 
|  | 3525 | if (install_wavefront () < 0) { | 
|  | 3526 | return -EIO; | 
|  | 3527 | } | 
|  | 3528 |  | 
|  | 3529 | return 0; | 
|  | 3530 | } | 
|  | 3531 |  | 
|  | 3532 | static void __exit cleanup_wavfront (void) | 
|  | 3533 | { | 
|  | 3534 | uninstall_wavefront (); | 
|  | 3535 | } | 
|  | 3536 |  | 
|  | 3537 | module_init(init_wavfront); | 
|  | 3538 | module_exit(cleanup_wavfront); |