// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) by Paul Barton-Davis 1998-1999 * * Some portions of this file are taken from work that is * copyright (C) by Hannu Savolainen 1993-1996
*/
/* * An ALSA lowlevel driver for Turtle Beach ICS2115 wavetable synth * (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. *
*/
staticint wf_raw = 0; /* we normally check for "raw state" to firmware loading. if non-zero, then during driver loading, the state of the board is ignored, and we reset the board and load the firmware anyway.
*/
staticint 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.
*/
staticint debug_default = 0; /* 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 */
#define DEFAULT_OSPATH "wavefront.os" staticchar *ospath = DEFAULT_OSPATH; /* the firmware file name */
staticint wait_usecs = 150; /* This magic number seems to give pretty optimal throughput based on my limited experimentation. If you want to play around with it and find a better value, be my guest. Remember, the idea is to get a number that causes us to just busy wait for as many WaveFront commands as possible, without coming up with a number so large that we hog the whole CPU.
Specifically, with this number, out of about 134,000 status waits, only about 250 result in a sleep.
*/
staticint sleep_interval = 100; /* HZ/sleep_interval seconds per sleep */ staticint sleep_tries = 50; /* number of times we'll try to sleep */
staticint reset_time = 2; /* hundreths of a second we wait after a HW reset for the expected interrupt.
*/
staticint ramcheck_time = 20; /* time in seconds to wait while ROM code checks on-board RAM.
*/
staticint osrun_time = 10; /* time in seconds we wait for the OS to start running.
*/
module_param(wf_raw, int, 0444);
MODULE_PARM_DESC(wf_raw, "if non-zero, assume that we need to boot the OS");
module_param(fx_raw, int, 0444);
MODULE_PARM_DESC(fx_raw, "if non-zero, assume that the FX process needs help");
module_param(debug_default, int, 0444);
MODULE_PARM_DESC(debug_default, "debug parameters for card initialization");
module_param(wait_usecs, int, 0444);
MODULE_PARM_DESC(wait_usecs, "how long to wait without sleeping, usecs");
module_param(sleep_interval, int, 0444);
MODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply");
module_param(sleep_tries, int, 0444);
MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait");
module_param(ospath, charp, 0444);
MODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware");
module_param(reset_time, int, 0444);
MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect");
module_param(ramcheck_time, int, 0444);
MODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test");
module_param(osrun_time, int, 0444);
MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS");
/* 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.
*/
/* This command requires a variable number of bytes to be written. There is a hack in snd_wavefront_cmd() to support this. The actual count is passed in as the read buffer ptr, cast appropriately. Ugh.
*/
/* 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.
*/
for (i = 0; i < wfcmd->write_cnt; i++) { if (wavefront_write (dev, 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]);
}
}
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.
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;
};
staticint
demunge_int32 (unsignedchar* src, int src_size)
{ int i; int outval = 0;
for (i = src_size - 1; i >= 0; i--) {
outval=(outval<<7)+src[i];
}
/* 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.
***********************************************************************/
staticint
wavefront_delete_sample (snd_wavefront_t *dev, int sample_num)
if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
dev_warn(dev->card->dev, "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:
dev_err(dev->card->dev, "unknown sample type for slot %d (0x%x)\n",
i, rbuf[0]);
}
if (rbuf[0] != WF_ST_EMPTY) {
dev->samples_used++;
}
}
{ /* 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.
*/
u16 sample_short = 0;
u32 length;
u16 __user *data_end = NULL; unsignedint i; constunsignedint max_blksize = 4096/2; unsignedint written; unsignedint blocksize; int dma_ack; int blocknum; unsignedchar sample_hdr[WF_SAMPLE_HDR_BYTES]; unsignedchar *shptr; int skip = 0; int initial_skip = 0;
if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { int x;
x = wavefront_find_free_sample(dev); if (x < 0) return -ENOMEM;
dev_info(dev->card->dev, "unspecified sample => %d\n", x);
header->number = x;
}
if (header->number >= WF_MAX_SAMPLE) return -EINVAL;
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) {
dev_err(dev->card->dev, "sample slot %d write protected\n",
header->number); return -EACCES;
}
}
wavefront_delete_sample (dev, header->number);
}
if (header->size) {
dev->freemem = wavefront_freemem (dev);
if (dev->freemem < (int)header->size) {
dev_err(dev->card->dev, "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) {
dev_err(dev->card->dev, "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;
}
/* 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.
*/
/* Why is this nybblified, when the MSB is *always* zero ? Anyway, we can't take address of bitfield, so make a good-faith guess at where it starts.
*/
staticint
wavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header)
{ int i; int num_samples; unsignedchar *msample_hdr;
if (header->number >= WF_MAX_SAMPLE) return -EINVAL;
msample_hdr = kmalloc(WF_MSAMPLE_BYTES, GFP_KERNEL); if (! msample_hdr) return -ENOMEM;
munge_int32 (header->number, &msample_hdr[0], 2);
/* You'll recall at this point that the "number of samples" value in a wavefront_multisample struct is actually the log2 of the real number of samples.
*/
DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n",
header->number,
header->hdr.ms.NumberOfSamples,
num_samples);
for (i = 0; i < num_samples; i++) {
DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n",
i, header->hdr.ms.SampleNumber[i]);
munge_int32 (header->hdr.ms.SampleNumber[i],
&msample_hdr[3+(i*2)], 2);
}
/* Need a hack here to pass in the number of bytes to be written to the synth. This is ugly, and perhaps one day, I'll fix it.
*/
if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE,
(unsignedchar *) (long) ((num_samples*2)+3),
msample_hdr)) {
dev_err(dev->card->dev, "download of multisample failed.\n");
kfree(msample_hdr); return -EIO;
}
/* The board doesn't send us an exact copy of a "wavefront_sample" in response to an Upload Sample Header command. Instead, we have to convert the data format back into our data structure, just as in the Download Sample command, where we have to do something very similar in the reverse direction.
*/
case WFC_UPLOAD_MULTISAMPLE: /* multisamples have to be handled differently, and cannot be dealt with properly by snd_wavefront_cmd() alone.
*/
wc->status = wavefront_fetch_multisample
(dev, (wavefront_patch_info *) wc->rbuf); return 0;
case WFC_UPLOAD_SAMPLE_ALIAS:
dev_err(dev->card->dev, "support for sample alias upload being considered.\n");
wc->status = EINVAL; return -EINVAL;
}
In particular, if the command was an upload, demunge the data so that the user-level doesn't have to think about it.
*/
if (wc->status == 0) { switch (wc->cmd) { /* intercept any freemem requests so that we know we are always current with the user-level view of things.
*/
case WFC_REPORT_FREE_MEMORY:
dev->freemem = demunge_int32 (wc->rbuf, 4); break;
case WFC_UPLOAD_PATCH:
demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); break;
case WFC_UPLOAD_PROGRAM:
demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); break;
case WFC_UPLOAD_EDRUM_PROGRAM:
demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); break;
case WFC_UPLOAD_SAMPLE_HEADER:
process_sample_hdr (wc->rbuf); break;
case WFC_UPLOAD_SAMPLE_ALIAS:
dev_err(dev->card->dev, "support for sample aliases still being considered.\n"); break;
case WFC_VMIDI_OFF:
snd_wavefront_midi_disable_virtual (acard); break;
case WFC_VMIDI_ON:
snd_wavefront_midi_enable_virtual (acard); break;
}
}
return 0;
}
int
snd_wavefront_synth_open (struct snd_hwdep *hw, struct file *file)
/* Some comments on interrupts. I attempted a version of this driver that used interrupts throughout the code instead of doing busy and/or sleep-waiting. Alas, it appears that once the Motorola firmware is downloaded, the card *never* generates an RX interrupt. These are successfully generated during firmware loading, and after that wavefront_status() reports that an interrupt is pending on the card from time to time, but it never seems to be delivered to this driver. Note also that wavefront_status() continues to report that RX interrupts are enabled, suggesting that I didn't goof up and disable them by mistake.
Thus, I stepped back to a prior version of wavefront_wait(), the only place where this really matters. Its sad, but I've looked through the code to check on things, and I really feel certain that the Motorola firmware prevents RX-ready interrupts.
*/
if ((wavefront_status(dev) & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { return;
}
/* At this point, the board is in reset, and the H/W initialization register is accessed at the same address as the data port. Bit 7 - Enable IRQ Driver 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. Bit 6 - MIDI Interface Select
0 - Use the MIDI Input from the 26-pin WaveBlaster compatible header as the serial MIDI source 1 - Use the MIDI Input from the 9-pin D connector as the serial MIDI source. Bits 5:3 - IRQ Selection 0 0 0 - IRQ 2/9 0 0 1 - IRQ 5 0 1 0 - IRQ 12 0 1 1 - IRQ 15 1 0 0 - Reserved 1 0 1 - Reserved 1 1 0 - Reserved 1 1 1 - Reserved Bits 2:1 - Reserved Bit 0 - Disable Boot ROM 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM 1 - memory accesses to 03FC30-03FFFFH are directed to external storage.
*/
/* Note: data port is now the data port, not the h/w initialization port.
*/
if (!dev->irq_ok) {
dev_err(dev->card->dev, "intr not received after h/w un-reset.\n"); goto gone_bad;
}
/* Note: data port is now the data port, not the h/w initialization port.
At this point, only "HW VERSION" or "DOWNLOAD OS" commands will work. So, issue one of them, and wait for TX interrupt. This can take a *long* time after a cold boot, while the ISC ROM does its RAM test. The SDK says up to 4 seconds - with 12MB of RAM on a Tropez+, it takes a lot longer than that (~16secs). Note that the card understands the difference between a warm and a cold boot, so subsequent ISC2115 reboots (say, caused by module reloading) will get through this much faster.
XXX Interesting question: why is no RX interrupt received first ?
*/
if (dev->israw) { if (wavefront_download_firmware (dev, ospath)) { goto gone_bad;
}
dev->israw = 0;
/* Wait for the OS to get running. The protocol for this is non-obvious, and was determined by using port-IO tracing in DOSemu and some experimentation here. Rather than using timed waits, use interrupts creatively.
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.