Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | ||
155542c2 AB |
154 | static 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 | */ | |
1da177e4 LT |
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 | \f | |
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 | \f | |
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 | \f | |
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 | \f | |
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 | \f | |
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 | ||
155542c2 | 2914 | static void |
1da177e4 LT |
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); |