diff options
Diffstat (limited to 'sound/oss/wavfront.c')
-rw-r--r-- | sound/oss/wavfront.c | 3554 |
1 files changed, 0 insertions, 3554 deletions
diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c deleted file mode 100644 index 1dec3958cc7..00000000000 --- a/sound/oss/wavfront.c +++ /dev/null @@ -1,3554 +0,0 @@ -/* -*- linux-c -*- - * - * sound/wavfront.c - * - * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus) - * - * This driver supports the onboard wavetable synthesizer (an ICS2115), - * including patch, sample and program loading and unloading, conversion - * of GUS patches during loading, and full user-level access to all - * WaveFront commands. It tries to provide semi-intelligent patch and - * sample management as well. - * - * It also provides support for the ICS emulation of an MPU-401. Full - * support for the ICS emulation's "virtual MIDI mode" is provided in - * wf_midi.c. - * - * Support is also provided for the Tropez Plus' onboard FX processor, - * a Yamaha YSS225. Currently, code exists to configure the YSS225, - * and there is an interface allowing tweaking of any of its memory - * addresses. However, I have been unable to decipher the logical - * positioning of the configuration info for various effects, so for - * now, you just get the YSS225 in the same state as Turtle Beach's - * "SETUPSND.EXE" utility leaves it. - * - * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co], - * This chip also controls the configuration of the card: the wavefront - * synth is logical unit 4. - * - * - * Supported devices: - * - * /dev/dsp - using cs4232+ad1848 modules, OSS compatible - * /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible - * /dev/synth00 - raw synth interface - * - ********************************************************************** - * - * Copyright (C) by Paul Barton-Davis 1998 - * - * Some portions of this file are taken from work that is - * copyright (C) by Hannu Savolainen 1993-1996 - * - * Although the relevant code here is all new, the handling of - * sample/alias/multi- samples is entirely based on a driver by Matt - * Martin and Rutger Nijlunsing which demonstrated how to get things - * to work correctly. The GUS patch loading code has been almost - * unaltered by me, except to fit formatting and function names in the - * rest of the file. Many thanks to them. - * - * Appreciation and thanks to Hannu Savolainen for his early work on the Maui - * driver, and answering a few questions while this one was developed. - * - * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their - * complete lack of help in developing this driver, and in particular - * for their utter silence in response to questions about undocumented - * aspects of configuring a WaveFront soundcard, particularly the - * effects processor. - * - * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $ - * - * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * Changes: - * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> - * Added some __init and __initdata to entries in yss225.c - */ - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> -#include <linux/ptrace.h> -#include <linux/fcntl.h> -#include <linux/syscalls.h> -#include <linux/ioport.h> -#include <linux/spinlock.h> -#include <linux/interrupt.h> -#include <linux/config.h> - -#include <linux/delay.h> - -#include "sound_config.h" - -#include <linux/wavefront.h> - -#define _MIDI_SYNTH_C_ -#define MIDI_SYNTH_NAME "WaveFront MIDI" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -/* Compile-time control of the extent to which OSS is supported. - - I consider /dev/sequencer to be an anachronism, but given its - widespread usage by various Linux MIDI software, it seems worth - offering support to it if it's not too painful. Instead of using - /dev/sequencer, I recommend: - - for synth programming and patch loading: /dev/synthNN - for kernel-synchronized MIDI sequencing: the ALSA sequencer - for direct MIDI control: /dev/midiNN - - I have never tried static compilation into the kernel. The #if's - for this are really just notes to myself about what the code is - for. -*/ - -#define OSS_SUPPORT_SEQ 0x1 /* use of /dev/sequencer */ -#define OSS_SUPPORT_STATIC_INSTALL 0x2 /* static compilation into kernel */ - -#define OSS_SUPPORT_LEVEL 0x1 /* just /dev/sequencer for now */ - -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ -static int (*midi_load_patch) (int devno, int format, const char __user *addr, - int offs, int count, int pmgr_flag) = NULL; -#endif /* OSS_SUPPORT_SEQ */ - -/* if WF_DEBUG not defined, no run-time debugging messages will - be available via the debug flag setting. Given the current - beta state of the driver, this will remain set until a future - version. -*/ - -#define WF_DEBUG 1 - -#ifdef WF_DEBUG - -/* Thank goodness for gcc's preprocessor ... */ - -#define DPRINT(cond, format, args...) \ - if ((dev.debug & (cond)) == (cond)) { \ - printk (KERN_DEBUG LOGNAME format, ## args); \ - } -#else -#define DPRINT(cond, format, args...) -#endif - -#define LOGNAME "WaveFront: " - -/* bitmasks for WaveFront status port value */ - -#define STAT_RINTR_ENABLED 0x01 -#define STAT_CAN_READ 0x02 -#define STAT_INTR_READ 0x04 -#define STAT_WINTR_ENABLED 0x10 -#define STAT_CAN_WRITE 0x20 -#define STAT_INTR_WRITE 0x40 - -/*** Module-accessible parameters ***************************************/ - -static int wf_raw; /* we normally check for "raw state" to firmware - loading. if set, then during driver loading, the - state of the board is ignored, and we reset the - board and load the firmware anyway. - */ - -static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in - whatever state it is when the driver is loaded. - The default is to download the microprogram and - associated coefficients to set it up for "default" - operation, whatever that means. - */ - -static int debug_default; /* you can set this to control debugging - during driver loading. it takes any combination - of the WF_DEBUG_* flags defined in - wavefront.h - */ - -/* XXX this needs to be made firmware and hardware version dependent */ - -static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed - version of the WaveFront OS - */ - -static int wait_polls = 2000; /* This is a number of tries we poll the - status register before resorting to sleeping. - WaveFront being an ISA card each poll takes - about 1.2us. So before going to - sleep we wait up to 2.4ms in a loop. - */ - -static int sleep_length = HZ/100; /* This says how long we're going to - sleep between polls. - 10ms sounds reasonable for fast response. - */ - -static int sleep_tries = 50; /* Wait for status 0.5 seconds total. */ - -static int reset_time = 2; /* hundreths of a second we wait after a HW reset for - the expected interrupt. - */ - -static int ramcheck_time = 20; /* time in seconds to wait while ROM code - checks on-board RAM. - */ - -static int osrun_time = 10; /* time in seconds we wait for the OS to - start running. - */ - -module_param(wf_raw, int, 0); -module_param(fx_raw, int, 0); -module_param(debug_default, int, 0); -module_param(wait_polls, int, 0); -module_param(sleep_length, int, 0); -module_param(sleep_tries, int, 0); -module_param(ospath, charp, 0); -module_param(reset_time, int, 0); -module_param(ramcheck_time, int, 0); -module_param(osrun_time, int, 0); - -/***************************************************************************/ - -/* Note: because this module doesn't export any symbols, this really isn't - a global variable, even if it looks like one. I was quite confused by - this when I started writing this as a (newer) module -- pbd. -*/ - -struct wf_config { - int devno; /* device number from kernel */ - int irq; /* "you were one, one of the few ..." */ - int base; /* low i/o port address */ - -#define mpu_data_port base -#define mpu_command_port base + 1 /* write semantics */ -#define mpu_status_port base + 1 /* read semantics */ -#define data_port base + 2 -#define status_port base + 3 /* read semantics */ -#define control_port base + 3 /* write semantics */ -#define block_port base + 4 /* 16 bit, writeonly */ -#define last_block_port base + 6 /* 16 bit, writeonly */ - - /* FX ports. These are mapped through the ICS2115 to the YS225. - The ICS2115 takes care of flipping the relevant pins on the - YS225 so that access to each of these ports does the right - thing. Note: these are NOT documented by Turtle Beach. - */ - -#define fx_status base + 8 -#define fx_op base + 8 -#define fx_lcr base + 9 -#define fx_dsp_addr base + 0xa -#define fx_dsp_page base + 0xb -#define fx_dsp_lsb base + 0xc -#define fx_dsp_msb base + 0xd -#define fx_mod_addr base + 0xe -#define fx_mod_data base + 0xf - - volatile int irq_ok; /* set by interrupt handler */ - volatile int irq_cnt; /* ditto */ - int opened; /* flag, holds open(2) mode */ - char debug; /* debugging flags */ - int freemem; /* installed RAM, in bytes */ - - int synth_dev; /* devno for "raw" synth */ - int mididev; /* devno for internal MIDI */ - int ext_mididev; /* devno for external MIDI */ - int fx_mididev; /* devno for FX MIDI interface */ -#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ - int oss_dev; /* devno for OSS sequencer synth */ -#endif /* OSS_SUPPORT_SEQ */ - - char fw_version[2]; /* major = [0], minor = [1] */ - char hw_version[2]; /* major = [0], minor = [1] */ - char israw; /* needs Motorola microcode */ - char has_fx; /* has FX processor (Tropez+) */ - char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */ - char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */ - char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */ - int samples_used; /* how many */ - char interrupts_on; /* h/w MPU interrupts enabled ? */ - char rom_samples_rdonly; /* can we write on ROM samples */ - wait_queue_head_t interrupt_sleeper; -} dev; - -static DEFINE_SPINLOCK(lock); -static int detect_wffx(void); -static int wffx_ioctl (wavefront_fx_info *); -static int wffx_init (void); - -static int wavefront_delete_sample (int sampnum); -static int wavefront_find_free_sample (void); - -/* From wf_midi.c */ - -extern int virtual_midi_enable (void); -extern int virtual_midi_disable (void); -extern int detect_wf_mpu (int, int); -extern int install_wf_mpu (void); -extern int uninstall_wf_mpu (void); - -typedef struct { - int cmd; - char *action; - unsigned int read_cnt; - unsigned int write_cnt; - int need_ack; -} wavefront_command; - -static struct { - int errno; - const char *errstr; -} wavefront_errors[] = { - { 0x01, "Bad sample number" }, - { 0x02, "Out of sample memory" }, - { 0x03, "Bad patch number" }, - { 0x04, "Error in number of voices" }, - { 0x06, "Sample load already in progress" }, - { 0x0B, "No sample load request pending" }, - { 0x0E, "Bad MIDI channel number" }, - { 0x10, "Download Record Error" }, - { 0x80, "Success" }, - { 0 } -}; - -#define NEEDS_ACK 1 - -static wavefront_command wavefront_commands[] = { - { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK }, - { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0}, - { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK }, - { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 }, - { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK }, - { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 }, - { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK }, - { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK }, - { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 }, - { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK }, - { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK }, - { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK }, - { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK }, - { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 }, - { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 }, - { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 }, - { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 }, - { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 }, - { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 }, - { WFC_DOWNLOAD_SAMPLE, "download sample", - 0, WF_SAMPLE_BYTES, NEEDS_ACK }, - { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK}, - { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header", - 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK }, - { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 }, - - /* This command requires a variable number of bytes to be written. - There is a hack in wavefront_cmd() to support this. The actual - count is passed in as the read buffer ptr, cast appropriately. - Ugh. - */ - - { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK }, - - /* This one is a hack as well. We just read the first byte of the - response, don't fetch an ACK, and leave the rest to the - calling function. Ugly, ugly, ugly. - */ - - { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 }, - { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias", - 0, WF_ALIAS_BYTES, NEEDS_ACK }, - { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0}, - { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK }, - { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 }, - { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" }, - { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 }, - { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK }, - { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 }, - { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK }, - { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 }, - { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9, - NEEDS_ACK}, - { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0}, - { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel", - 0, 1, NEEDS_ACK }, - { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, - { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", - 32, 0, 0 }, - { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, - { 0x00 } -}; - -static const char * -wavefront_errorstr (int errnum) - -{ - int i; - - for (i = 0; wavefront_errors[i].errstr; i++) { - if (wavefront_errors[i].errno == errnum) { - return wavefront_errors[i].errstr; - } - } - - return "Unknown WaveFront error"; -} - -static wavefront_command * -wavefront_get_command (int cmd) - -{ - int i; - - for (i = 0; wavefront_commands[i].cmd != 0; i++) { - if (cmd == wavefront_commands[i].cmd) { - return &wavefront_commands[i]; - } - } - - return (wavefront_command *) 0; -} - -static inline int -wavefront_status (void) - -{ - return inb (dev.status_port); -} - -static int -wavefront_wait (int mask) - -{ - int i; - - for (i = 0; i < wait_polls; i++) - if (wavefront_status() & mask) - return 1; - - for (i = 0; i < sleep_tries; i++) { - - if (wavefront_status() & mask) { - set_current_state(TASK_RUNNING); - return 1; - } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(sleep_length); - if (signal_pending(current)) - break; - } - - set_current_state(TASK_RUNNING); - return 0; -} - -static int -wavefront_read (void) - -{ - if (wavefront_wait (STAT_CAN_READ)) - return inb (dev.data_port); - - DPRINT (WF_DEBUG_DATA, "read timeout.\n"); - - return -1; -} - -static int -wavefront_write (unsigned char data) - -{ - if (wavefront_wait (STAT_CAN_WRITE)) { - outb (data, dev.data_port); - return 0; - } - - DPRINT (WF_DEBUG_DATA, "write timeout.\n"); - - return -1; -} - -static int -wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf) - -{ - int ack; - int i; - int c; - wavefront_command *wfcmd; - - if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) { - printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n", - cmd); - return 1; - } - - /* Hack to handle the one variable-size write command. See - wavefront_send_multisample() for the other half of this - gross and ugly strategy. - */ - - if (cmd == WFC_DOWNLOAD_MULTISAMPLE) { - wfcmd->write_cnt = (unsigned int) rbuf; - rbuf = NULL; - } - - DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n", - cmd, wfcmd->action, wfcmd->read_cnt, - wfcmd->write_cnt, wfcmd->need_ack); - - if (wavefront_write (cmd)) { - DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request " - "0x%x [%s].\n", - cmd, wfcmd->action); - return 1; - } - - if (wfcmd->write_cnt > 0) { - DPRINT (WF_DEBUG_DATA, "writing %d bytes " - "for 0x%x\n", - wfcmd->write_cnt, cmd); - - for (i = 0; i < wfcmd->write_cnt; i++) { - if (wavefront_write (wbuf[i])) { - DPRINT (WF_DEBUG_IO, "bad write for byte " - "%d of 0x%x [%s].\n", - i, cmd, wfcmd->action); - return 1; - } - - DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n", - i, wbuf[i]); - } - } - - if (wfcmd->read_cnt > 0) { - DPRINT (WF_DEBUG_DATA, "reading %d ints " - "for 0x%x\n", - wfcmd->read_cnt, cmd); - - for (i = 0; i < wfcmd->read_cnt; i++) { - - if ((c = wavefront_read()) == -1) { - DPRINT (WF_DEBUG_IO, "bad read for byte " - "%d of 0x%x [%s].\n", - i, cmd, wfcmd->action); - return 1; - } - - /* Now handle errors. Lots of special cases here */ - - if (c == 0xff) { - if ((c = wavefront_read ()) == -1) { - DPRINT (WF_DEBUG_IO, "bad read for " - "error byte at " - "read byte %d " - "of 0x%x [%s].\n", - i, cmd, - wfcmd->action); - return 1; - } - - /* Can you believe this madness ? */ - - if (c == 1 && - wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { - rbuf[0] = WF_ST_EMPTY; - return (0); - - } else if (c == 3 && - wfcmd->cmd == WFC_UPLOAD_PATCH) { - - return 3; - - } else if (c == 1 && - wfcmd->cmd == WFC_UPLOAD_PROGRAM) { - - return 1; - - } else { - - DPRINT (WF_DEBUG_IO, "error %d (%s) " - "during " - "read for byte " - "%d of 0x%x " - "[%s].\n", - c, - wavefront_errorstr (c), - i, cmd, - wfcmd->action); - return 1; - - } - - } else { - rbuf[i] = c; - } - - DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]); - } - } - - if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { - - DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd); - - /* Some commands need an ACK, but return zero instead - of the standard value. - */ - - if ((ack = wavefront_read()) == 0) { - ack = WF_ACK; - } - - if (ack != WF_ACK) { - if (ack == -1) { - DPRINT (WF_DEBUG_IO, "cannot read ack for " - "0x%x [%s].\n", - cmd, wfcmd->action); - return 1; - - } else { - int err = -1; /* something unknown */ - - if (ack == 0xff) { /* explicit error */ - - if ((err = wavefront_read ()) == -1) { - DPRINT (WF_DEBUG_DATA, - "cannot read err " - "for 0x%x [%s].\n", - cmd, wfcmd->action); - } - } - - DPRINT (WF_DEBUG_IO, "0x%x [%s] " - "failed (0x%x, 0x%x, %s)\n", - cmd, wfcmd->action, ack, err, - wavefront_errorstr (err)); - - return -err; - } - } - - DPRINT (WF_DEBUG_DATA, "ack received " - "for 0x%x [%s]\n", - cmd, wfcmd->action); - } else { - - DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need " - "ACK (%d,%d,%d)\n", - cmd, wfcmd->action, wfcmd->read_cnt, - wfcmd->write_cnt, wfcmd->need_ack); - } - - return 0; - -} - -/*********************************************************************** -WaveFront: data munging - -Things here are weird. All data written to the board cannot -have its most significant bit set. Any data item with values -potentially > 0x7F (127) must be split across multiple bytes. - -Sometimes, we need to munge numeric values that are represented on -the x86 side as 8-32 bit values. Sometimes, we need to munge data -that is represented on the x86 side as an array of bytes. The most -efficient approach to handling both cases seems to be to use 2 -different functions for munging and 2 for de-munging. This avoids -weird casting and worrying about bit-level offsets. - -**********************************************************************/ - -static -unsigned char * -munge_int32 (unsigned int src, - unsigned char *dst, - unsigned int dst_size) -{ - int i; - - for (i = 0;i < dst_size; i++) { - *dst = src & 0x7F; /* Mask high bit of LSB */ - src = src >> 7; /* Rotate Right 7 bits */ - /* Note: we leave the upper bits in place */ - - dst++; - }; - return dst; -}; - -static int -demunge_int32 (unsigned char* src, int src_size) - -{ - int i; - int outval = 0; - - for (i = src_size - 1; i >= 0; i--) { - outval=(outval<<7)+src[i]; - } - - return outval; -}; - -static -unsigned char * -munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size) - -{ - int i; - unsigned int last = dst_size / 2; - - for (i = 0; i < last; i++) { - *dst++ = src[i] & 0x7f; - *dst++ = src[i] >> 7; - } - return dst; -} - -static -unsigned char * -demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) - -{ - int i; - unsigned char *end = src + src_bytes; - - end = src + src_bytes; - - /* NOTE: src and dst *CAN* point to the same address */ - - for (i = 0; src != end; i++) { - dst[i] = *src++; - dst[i] |= (*src++)<<7; - } - - return dst; -} - -/*********************************************************************** -WaveFront: sample, patch and program management. -***********************************************************************/ - -static int -wavefront_delete_sample (int sample_num) - -{ - unsigned char wbuf[2]; - int x; - - wbuf[0] = sample_num & 0x7f; - wbuf[1] = sample_num >> 7; - - if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { - dev.sample_status[sample_num] = WF_ST_EMPTY; - } - - return x; -} - -static int -wavefront_get_sample_status (int assume_rom) - -{ - int i; - unsigned char rbuf[32], wbuf[32]; - unsigned int sc_real, sc_alias, sc_multi; - - /* check sample status */ - - if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME "cannot request sample count.\n"); - return -1; - } - - sc_real = sc_alias = sc_multi = dev.samples_used = 0; - - for (i = 0; i < WF_MAX_SAMPLE; i++) { - - wbuf[0] = i & 0x7f; - wbuf[1] = i >> 7; - - if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { - printk (KERN_WARNING LOGNAME - "cannot identify sample " - "type of slot %d\n", i); - dev.sample_status[i] = WF_ST_EMPTY; - continue; - } - - dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); - - if (assume_rom) { - dev.sample_status[i] |= WF_SLOT_ROM; - } - - switch (rbuf[0] & WF_ST_MASK) { - case WF_ST_SAMPLE: - sc_real++; - break; - case WF_ST_MULTISAMPLE: - sc_multi++; - break; - case WF_ST_ALIAS: - sc_alias++; - break; - case WF_ST_EMPTY: - break; - - default: - printk (KERN_WARNING LOGNAME "unknown sample type for " - "slot %d (0x%x)\n", - i, rbuf[0]); - } - - if (rbuf[0] != WF_ST_EMPTY) { - dev.samples_used++; - } - } - - printk (KERN_INFO LOGNAME - "%d samples used (%d real, %d aliases, %d multi), " - "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi, - WF_MAX_SAMPLE - dev.samples_used); - - - return (0); - -} - -static int -wavefront_get_patch_status (void) - -{ - unsigned char patchbuf[WF_PATCH_BYTES]; - unsigned char patchnum[2]; - wavefront_patch *p; - int i, x, cnt, cnt2; - - for (i = 0; i < WF_MAX_PATCH; i++) { - patchnum[0] = i & 0x7f; - patchnum[1] = i >> 7; - - if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf, - patchnum)) == 0) { - - dev.patch_status[i] |= WF_SLOT_FILLED; - p = (wavefront_patch *) patchbuf; - dev.sample_status - [p->sample_number|(p->sample_msb<<7)] |= - WF_SLOT_USED; - - } else if (x == 3) { /* Bad patch number */ - dev.patch_status[i] = 0; - } else { - printk (KERN_ERR LOGNAME "upload patch " - "error 0x%x\n", x); - dev.patch_status[i] = 0; - return 1; - } - } - - /* program status has already filled in slot_used bits */ - - for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { - if (dev.patch_status[i] & WF_SLOT_FILLED) { - cnt++; - } - if (dev.patch_status[i] & WF_SLOT_USED) { - cnt2++; - } - - } - printk (KERN_INFO LOGNAME - "%d patch slots filled, %d in use\n", cnt, cnt2); - - return (0); -} - -static int -wavefront_get_program_status (void) - -{ - unsigned char progbuf[WF_PROGRAM_BYTES]; - wavefront_program prog; - unsigned char prognum; - int i, x, l, cnt; - - for (i = 0; i < WF_MAX_PROGRAM; i++) { - prognum = i; - - if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf, - &prognum)) == 0) { - - dev.prog_status[i] |= WF_SLOT_USED; - - demunge_buf (progbuf, (unsigned char *) &prog, - WF_PROGRAM_BYTES); - - for (l = 0; l < WF_NUM_LAYERS; l++) { - if (prog.layer[l].mute) { - dev.patch_status - [prog.layer[l].patch_number] |= - WF_SLOT_USED; - } - } - } else if (x == 1) { /* Bad program number */ - dev.prog_status[i] = 0; - } else { - printk (KERN_ERR LOGNAME "upload program " - "error 0x%x\n", x); - dev.prog_status[i] = 0; - } - } - - for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { - if (dev.prog_status[i]) { - cnt++; - } - } - - printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt); - - return (0); -} - -static int -wavefront_send_patch (wavefront_patch_info *header) - -{ - unsigned char buf[WF_PATCH_BYTES+2]; - unsigned char *bptr; - - DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", - header->number); - - dev.patch_status[header->number] |= WF_SLOT_FILLED; - - bptr = buf; - bptr = munge_int32 (header->number, buf, 2); - munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); - - if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) { - printk (KERN_ERR LOGNAME "download patch failed\n"); - return -(EIO); - } - - return (0); -} - -static int -wavefront_send_program (wavefront_patch_info *header) - -{ - unsigned char buf[WF_PROGRAM_BYTES+1]; - int i; - - DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", - header->number); - - dev.prog_status[header->number] = WF_SLOT_USED; - - /* XXX need to zero existing SLOT_USED bit for program_status[i] - where `i' is the program that's being (potentially) overwritten. - */ - - for (i = 0; i < WF_NUM_LAYERS; i++) { - if (header->hdr.pr.layer[i].mute) { - dev.patch_status[header->hdr.pr.layer[i].patch_number] |= - WF_SLOT_USED; - - /* XXX need to mark SLOT_USED for sample used by - patch_number, but this means we have to load it. Ick. - */ - } - } - - buf[0] = header->number; - munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); - - if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) { - printk (KERN_WARNING LOGNAME "download patch failed\n"); - return -(EIO); - } - - return (0); -} - -static int -wavefront_freemem (void) - -{ - char rbuf[8]; - - if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { - printk (KERN_WARNING LOGNAME "can't get memory stats.\n"); - return -1; - } else { - return demunge_int32 (rbuf, 4); - } -} - -static int -wavefront_send_sample (wavefront_patch_info *header, - UINT16 __user *dataptr, - int data_is_unsigned) - -{ - /* samples are downloaded via a 16-bit wide i/o port - (you could think of it as 2 adjacent 8-bit wide ports - but its less efficient that way). therefore, all - the blocksizes and so forth listed in the documentation, - and used conventionally to refer to sample sizes, - which are given in 8-bit units (bytes), need to be - divided by 2. - */ - - UINT16 sample_short; - UINT32 length; - UINT16 __user *data_end = NULL; - unsigned int i; - const int max_blksize = 4096/2; - unsigned int written; - unsigned int blocksize; - int dma_ack; - int blocknum; - unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; - unsigned char *shptr; - int skip = 0; - int initial_skip = 0; - - DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " - "type %d, %d bytes from %p\n", - header->size ? "" : "header ", - header->number, header->subkey, - header->size, - header->dataptr); - - if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { - int x; - - if ((x = wavefront_find_free_sample ()) < 0) { - return -ENOMEM; - } - printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x); - header->number = x; - } - - if (header->size) { - - /* XXX it's a debatable point whether or not RDONLY semantics - on the ROM samples should cover just the sample data or - the sample header. For now, it only covers the sample data, - so anyone is free at all times to rewrite sample headers. - - My reason for this is that we have the sample headers - available in the WFB file for General MIDI, and so these - can always be reset if needed. The sample data, however, - cannot be recovered without a complete reset and firmware - reload of the ICS2115, which is a very expensive operation. - - So, doing things this way allows us to honor the notion of - "RESETSAMPLES" reasonably cheaply. Note however, that this - is done purely at user level: there is no WFB parser in - this driver, and so a complete reset (back to General MIDI, - or theoretically some other configuration) is the - responsibility of the user level library. - - To try to do this in the kernel would be a little - crazy: we'd need 158K of kernel space just to hold - a copy of the patch/program/sample header data. - */ - - if (dev.rom_samples_rdonly) { - if (dev.sample_status[header->number] & WF_SLOT_ROM) { - printk (KERN_ERR LOGNAME "sample slot %d " - "write protected\n", - header->number); - return -EACCES; - } - } - - wavefront_delete_sample (header->number); - } - - if (header->size) { - dev.freemem = wavefront_freemem (); - - if (dev.freemem < header->size) { - printk (KERN_ERR LOGNAME - "insufficient memory to " - "load %d byte sample.\n", - header->size); - return -ENOMEM; - } - - } - - skip = WF_GET_CHANNEL(&header->hdr.s); - - if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { - printk (KERN_ERR LOGNAME "channel selection only " - "possible on 16-bit samples"); - return -(EINVAL); - } - - switch (skip) { - case 0: - initial_skip = 0; - skip = 1; - break; - case 1: - initial_skip = 0; - skip = 2; - break; - case 2: - initial_skip = 1; - skip = 2; - break; - case 3: - initial_skip = 2; - skip = 3; - break; - case 4: - initial_skip = 3; - skip = 4; - break; - case 5: - initial_skip = 4; - skip = 5; - break; - case 6: - initial_skip = 5; - skip = 6; - break; - } - - DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " - "initial skip = %d, skip = %d\n", - WF_GET_CHANNEL (&header->hdr.s), - initial_skip, skip); - - /* Be safe, and zero the "Unused" bits ... */ - - WF_SET_CHANNEL(&header->hdr.s, 0); - - /* adjust size for 16 bit samples by dividing by two. We always - send 16 bits per write, even for 8 bit samples, so the length - is always half the size of the sample data in bytes. - */ - - length = header->size / 2; - - /* the data we're sent has not been munged, and in fact, the - header we have to send isn't just a munged copy either. - so, build the sample header right here. - */ - - shptr = &sample_hdr[0]; - - shptr = munge_int32 (header->number, shptr, 2); - - if (header->size) { - shptr = munge_int32 (length, shptr, 4); - } - - /* Yes, a 4 byte result doesn't contain all of the offset bits, - but the offset only uses 24 bits. - */ - - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset), - shptr, 4); - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset), - shptr, 4); - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset), - shptr, 4); - shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), - shptr, 4); - - /* This one is truly weird. What kind of weirdo decided that in - a system dominated by 16 and 32 bit integers, they would use - a just 12 bits ? - */ - - shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); - - /* Why is this nybblified, when the MSB is *always* zero ? - |