162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (C) by Paul Barton-Davis 1998-1999 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Some portions of this file are taken from work that is 562306a36Sopenharmony_ci * copyright (C) by Hannu Savolainen 1993-1996 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * An ALSA lowlevel driver for Turtle Beach ICS2115 wavetable synth 1062306a36Sopenharmony_ci * (Maui, Tropez, Tropez Plus) 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * This driver supports the onboard wavetable synthesizer (an ICS2115), 1362306a36Sopenharmony_ci * including patch, sample and program loading and unloading, conversion 1462306a36Sopenharmony_ci * of GUS patches during loading, and full user-level access to all 1562306a36Sopenharmony_ci * WaveFront commands. It tries to provide semi-intelligent patch and 1662306a36Sopenharmony_ci * sample management as well. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <linux/io.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/init.h> 2362306a36Sopenharmony_ci#include <linux/delay.h> 2462306a36Sopenharmony_ci#include <linux/time.h> 2562306a36Sopenharmony_ci#include <linux/wait.h> 2662306a36Sopenharmony_ci#include <linux/sched/signal.h> 2762306a36Sopenharmony_ci#include <linux/firmware.h> 2862306a36Sopenharmony_ci#include <linux/moduleparam.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/module.h> 3162306a36Sopenharmony_ci#include <sound/core.h> 3262306a36Sopenharmony_ci#include <sound/snd_wavefront.h> 3362306a36Sopenharmony_ci#include <sound/initval.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int wf_raw = 0; /* we normally check for "raw state" to firmware 3662306a36Sopenharmony_ci loading. if non-zero, then during driver loading, the 3762306a36Sopenharmony_ci state of the board is ignored, and we reset the 3862306a36Sopenharmony_ci board and load the firmware anyway. 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int fx_raw = 1; /* if this is zero, we'll leave the FX processor in 4262306a36Sopenharmony_ci whatever state it is when the driver is loaded. 4362306a36Sopenharmony_ci The default is to download the microprogram and 4462306a36Sopenharmony_ci associated coefficients to set it up for "default" 4562306a36Sopenharmony_ci operation, whatever that means. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int debug_default = 0; /* you can set this to control debugging 4962306a36Sopenharmony_ci during driver loading. it takes any combination 5062306a36Sopenharmony_ci of the WF_DEBUG_* flags defined in 5162306a36Sopenharmony_ci wavefront.h 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* XXX this needs to be made firmware and hardware version dependent */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define DEFAULT_OSPATH "wavefront.os" 5762306a36Sopenharmony_cistatic char *ospath = DEFAULT_OSPATH; /* the firmware file name */ 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int wait_usecs = 150; /* This magic number seems to give pretty optimal 6062306a36Sopenharmony_ci throughput based on my limited experimentation. 6162306a36Sopenharmony_ci If you want to play around with it and find a better 6262306a36Sopenharmony_ci value, be my guest. Remember, the idea is to 6362306a36Sopenharmony_ci get a number that causes us to just busy wait 6462306a36Sopenharmony_ci for as many WaveFront commands as possible, without 6562306a36Sopenharmony_ci coming up with a number so large that we hog the 6662306a36Sopenharmony_ci whole CPU. 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci Specifically, with this number, out of about 134,000 6962306a36Sopenharmony_ci status waits, only about 250 result in a sleep. 7062306a36Sopenharmony_ci */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic int sleep_interval = 100; /* HZ/sleep_interval seconds per sleep */ 7362306a36Sopenharmony_cistatic int sleep_tries = 50; /* number of times we'll try to sleep */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int reset_time = 2; /* hundreths of a second we wait after a HW 7662306a36Sopenharmony_ci reset for the expected interrupt. 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int ramcheck_time = 20; /* time in seconds to wait while ROM code 8062306a36Sopenharmony_ci checks on-board RAM. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic int osrun_time = 10; /* time in seconds we wait for the OS to 8462306a36Sopenharmony_ci start running. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cimodule_param(wf_raw, int, 0444); 8762306a36Sopenharmony_ciMODULE_PARM_DESC(wf_raw, "if non-zero, assume that we need to boot the OS"); 8862306a36Sopenharmony_cimodule_param(fx_raw, int, 0444); 8962306a36Sopenharmony_ciMODULE_PARM_DESC(fx_raw, "if non-zero, assume that the FX process needs help"); 9062306a36Sopenharmony_cimodule_param(debug_default, int, 0444); 9162306a36Sopenharmony_ciMODULE_PARM_DESC(debug_default, "debug parameters for card initialization"); 9262306a36Sopenharmony_cimodule_param(wait_usecs, int, 0444); 9362306a36Sopenharmony_ciMODULE_PARM_DESC(wait_usecs, "how long to wait without sleeping, usecs"); 9462306a36Sopenharmony_cimodule_param(sleep_interval, int, 0444); 9562306a36Sopenharmony_ciMODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply"); 9662306a36Sopenharmony_cimodule_param(sleep_tries, int, 0444); 9762306a36Sopenharmony_ciMODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait"); 9862306a36Sopenharmony_cimodule_param(ospath, charp, 0444); 9962306a36Sopenharmony_ciMODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware"); 10062306a36Sopenharmony_cimodule_param(reset_time, int, 0444); 10162306a36Sopenharmony_ciMODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect"); 10262306a36Sopenharmony_cimodule_param(ramcheck_time, int, 0444); 10362306a36Sopenharmony_ciMODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test"); 10462306a36Sopenharmony_cimodule_param(osrun_time, int, 0444); 10562306a36Sopenharmony_ciMODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS"); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* if WF_DEBUG not defined, no run-time debugging messages will 10862306a36Sopenharmony_ci be available via the debug flag setting. Given the current 10962306a36Sopenharmony_ci beta state of the driver, this will remain set until a future 11062306a36Sopenharmony_ci version. 11162306a36Sopenharmony_ci*/ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define WF_DEBUG 1 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#ifdef WF_DEBUG 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define DPRINT(cond, ...) \ 11862306a36Sopenharmony_ci if ((dev->debug & (cond)) == (cond)) { \ 11962306a36Sopenharmony_ci snd_printk (__VA_ARGS__); \ 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci#else 12262306a36Sopenharmony_ci#define DPRINT(cond, args...) 12362306a36Sopenharmony_ci#endif /* WF_DEBUG */ 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define LOGNAME "WaveFront: " 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* bitmasks for WaveFront status port value */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#define STAT_RINTR_ENABLED 0x01 13062306a36Sopenharmony_ci#define STAT_CAN_READ 0x02 13162306a36Sopenharmony_ci#define STAT_INTR_READ 0x04 13262306a36Sopenharmony_ci#define STAT_WINTR_ENABLED 0x10 13362306a36Sopenharmony_ci#define STAT_CAN_WRITE 0x20 13462306a36Sopenharmony_ci#define STAT_INTR_WRITE 0x40 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int wavefront_delete_sample (snd_wavefront_t *, int sampnum); 13762306a36Sopenharmony_cistatic int wavefront_find_free_sample (snd_wavefront_t *); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct wavefront_command { 14062306a36Sopenharmony_ci int cmd; 14162306a36Sopenharmony_ci char *action; 14262306a36Sopenharmony_ci unsigned int read_cnt; 14362306a36Sopenharmony_ci unsigned int write_cnt; 14462306a36Sopenharmony_ci int need_ack; 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic struct { 14862306a36Sopenharmony_ci int errno; 14962306a36Sopenharmony_ci const char *errstr; 15062306a36Sopenharmony_ci} wavefront_errors[] = { 15162306a36Sopenharmony_ci { 0x01, "Bad sample number" }, 15262306a36Sopenharmony_ci { 0x02, "Out of sample memory" }, 15362306a36Sopenharmony_ci { 0x03, "Bad patch number" }, 15462306a36Sopenharmony_ci { 0x04, "Error in number of voices" }, 15562306a36Sopenharmony_ci { 0x06, "Sample load already in progress" }, 15662306a36Sopenharmony_ci { 0x0B, "No sample load request pending" }, 15762306a36Sopenharmony_ci { 0x0E, "Bad MIDI channel number" }, 15862306a36Sopenharmony_ci { 0x10, "Download Record Error" }, 15962306a36Sopenharmony_ci { 0x80, "Success" }, 16062306a36Sopenharmony_ci { 0x0 } 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci#define NEEDS_ACK 1 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic struct wavefront_command wavefront_commands[] = { 16662306a36Sopenharmony_ci { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK }, 16762306a36Sopenharmony_ci { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0}, 16862306a36Sopenharmony_ci { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK }, 16962306a36Sopenharmony_ci { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 }, 17062306a36Sopenharmony_ci { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK }, 17162306a36Sopenharmony_ci { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 }, 17262306a36Sopenharmony_ci { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK }, 17362306a36Sopenharmony_ci { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK }, 17462306a36Sopenharmony_ci { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 }, 17562306a36Sopenharmony_ci { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK }, 17662306a36Sopenharmony_ci { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK }, 17762306a36Sopenharmony_ci { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK }, 17862306a36Sopenharmony_ci { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK }, 17962306a36Sopenharmony_ci { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 }, 18062306a36Sopenharmony_ci { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 }, 18162306a36Sopenharmony_ci { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 }, 18262306a36Sopenharmony_ci { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 }, 18362306a36Sopenharmony_ci { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 }, 18462306a36Sopenharmony_ci { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 }, 18562306a36Sopenharmony_ci { WFC_DOWNLOAD_SAMPLE, "download sample", 18662306a36Sopenharmony_ci 0, WF_SAMPLE_BYTES, NEEDS_ACK }, 18762306a36Sopenharmony_ci { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK}, 18862306a36Sopenharmony_ci { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header", 18962306a36Sopenharmony_ci 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK }, 19062306a36Sopenharmony_ci { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 }, 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* This command requires a variable number of bytes to be written. 19362306a36Sopenharmony_ci There is a hack in snd_wavefront_cmd() to support this. The actual 19462306a36Sopenharmony_ci count is passed in as the read buffer ptr, cast appropriately. 19562306a36Sopenharmony_ci Ugh. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK }, 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* This one is a hack as well. We just read the first byte of the 20162306a36Sopenharmony_ci response, don't fetch an ACK, and leave the rest to the 20262306a36Sopenharmony_ci calling function. Ugly, ugly, ugly. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 }, 20662306a36Sopenharmony_ci { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias", 20762306a36Sopenharmony_ci 0, WF_ALIAS_BYTES, NEEDS_ACK }, 20862306a36Sopenharmony_ci { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0}, 20962306a36Sopenharmony_ci { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK }, 21062306a36Sopenharmony_ci { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 }, 21162306a36Sopenharmony_ci { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" }, 21262306a36Sopenharmony_ci { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 }, 21362306a36Sopenharmony_ci { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK }, 21462306a36Sopenharmony_ci { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 }, 21562306a36Sopenharmony_ci { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK }, 21662306a36Sopenharmony_ci { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 }, 21762306a36Sopenharmony_ci { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9, 21862306a36Sopenharmony_ci NEEDS_ACK}, 21962306a36Sopenharmony_ci { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0}, 22062306a36Sopenharmony_ci { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel", 22162306a36Sopenharmony_ci 0, 1, NEEDS_ACK }, 22262306a36Sopenharmony_ci { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, 22362306a36Sopenharmony_ci { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", 22462306a36Sopenharmony_ci 32, 0, 0 }, 22562306a36Sopenharmony_ci { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, 22662306a36Sopenharmony_ci { 0x00 } 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic const char * 23062306a36Sopenharmony_ciwavefront_errorstr (int errnum) 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci int i; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci for (i = 0; wavefront_errors[i].errstr; i++) { 23662306a36Sopenharmony_ci if (wavefront_errors[i].errno == errnum) { 23762306a36Sopenharmony_ci return wavefront_errors[i].errstr; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return "Unknown WaveFront error"; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic struct wavefront_command * 24562306a36Sopenharmony_ciwavefront_get_command (int cmd) 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci int i; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci for (i = 0; wavefront_commands[i].cmd != 0; i++) { 25162306a36Sopenharmony_ci if (cmd == wavefront_commands[i].cmd) { 25262306a36Sopenharmony_ci return &wavefront_commands[i]; 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return NULL; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic inline int 26062306a36Sopenharmony_ciwavefront_status (snd_wavefront_t *dev) 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci return inb (dev->status_port); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int 26762306a36Sopenharmony_ciwavefront_sleep (int limit) 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci schedule_timeout_interruptible(limit); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return signal_pending(current); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_cistatic int 27662306a36Sopenharmony_ciwavefront_wait (snd_wavefront_t *dev, int mask) 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int i; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Spin for a short period of time, because >99% of all 28262306a36Sopenharmony_ci requests to the WaveFront can be serviced inline like this. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci for (i = 0; i < wait_usecs; i += 5) { 28662306a36Sopenharmony_ci if (wavefront_status (dev) & mask) { 28762306a36Sopenharmony_ci return 1; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci udelay(5); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci for (i = 0; i < sleep_tries; i++) { 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (wavefront_status (dev) & mask) { 29562306a36Sopenharmony_ci return 1; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (wavefront_sleep (HZ/sleep_interval)) { 29962306a36Sopenharmony_ci return (0); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return (0); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int 30762306a36Sopenharmony_ciwavefront_read (snd_wavefront_t *dev) 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci if (wavefront_wait (dev, STAT_CAN_READ)) 31162306a36Sopenharmony_ci return inb (dev->data_port); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "read timeout.\n"); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return -1; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int 31962306a36Sopenharmony_ciwavefront_write (snd_wavefront_t *dev, unsigned char data) 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci if (wavefront_wait (dev, STAT_CAN_WRITE)) { 32362306a36Sopenharmony_ci outb (data, dev->data_port); 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "write timeout.\n"); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return -1; 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciint 33362306a36Sopenharmony_cisnd_wavefront_cmd (snd_wavefront_t *dev, 33462306a36Sopenharmony_ci int cmd, unsigned char *rbuf, unsigned char *wbuf) 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int ack; 33862306a36Sopenharmony_ci unsigned int i; 33962306a36Sopenharmony_ci int c; 34062306a36Sopenharmony_ci struct wavefront_command *wfcmd; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci wfcmd = wavefront_get_command(cmd); 34362306a36Sopenharmony_ci if (!wfcmd) { 34462306a36Sopenharmony_ci snd_printk ("command 0x%x not supported.\n", 34562306a36Sopenharmony_ci cmd); 34662306a36Sopenharmony_ci return 1; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Hack to handle the one variable-size write command. See 35062306a36Sopenharmony_ci wavefront_send_multisample() for the other half of this 35162306a36Sopenharmony_ci gross and ugly strategy. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (cmd == WFC_DOWNLOAD_MULTISAMPLE) { 35562306a36Sopenharmony_ci wfcmd->write_cnt = (unsigned long) rbuf; 35662306a36Sopenharmony_ci rbuf = NULL; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n", 36062306a36Sopenharmony_ci cmd, wfcmd->action, wfcmd->read_cnt, 36162306a36Sopenharmony_ci wfcmd->write_cnt, wfcmd->need_ack); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (wavefront_write (dev, cmd)) { 36462306a36Sopenharmony_ci DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request " 36562306a36Sopenharmony_ci "0x%x [%s].\n", 36662306a36Sopenharmony_ci cmd, wfcmd->action); 36762306a36Sopenharmony_ci return 1; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (wfcmd->write_cnt > 0) { 37162306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "writing %d bytes " 37262306a36Sopenharmony_ci "for 0x%x\n", 37362306a36Sopenharmony_ci wfcmd->write_cnt, cmd); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (i = 0; i < wfcmd->write_cnt; i++) { 37662306a36Sopenharmony_ci if (wavefront_write (dev, wbuf[i])) { 37762306a36Sopenharmony_ci DPRINT (WF_DEBUG_IO, "bad write for byte " 37862306a36Sopenharmony_ci "%d of 0x%x [%s].\n", 37962306a36Sopenharmony_ci i, cmd, wfcmd->action); 38062306a36Sopenharmony_ci return 1; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n", 38462306a36Sopenharmony_ci i, wbuf[i]); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (wfcmd->read_cnt > 0) { 38962306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "reading %d ints " 39062306a36Sopenharmony_ci "for 0x%x\n", 39162306a36Sopenharmony_ci wfcmd->read_cnt, cmd); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci for (i = 0; i < wfcmd->read_cnt; i++) { 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci c = wavefront_read(dev); 39662306a36Sopenharmony_ci if (c == -1) { 39762306a36Sopenharmony_ci DPRINT (WF_DEBUG_IO, "bad read for byte " 39862306a36Sopenharmony_ci "%d of 0x%x [%s].\n", 39962306a36Sopenharmony_ci i, cmd, wfcmd->action); 40062306a36Sopenharmony_ci return 1; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Now handle errors. Lots of special cases here */ 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (c == 0xff) { 40662306a36Sopenharmony_ci c = wavefront_read(dev); 40762306a36Sopenharmony_ci if (c == -1) { 40862306a36Sopenharmony_ci DPRINT (WF_DEBUG_IO, "bad read for " 40962306a36Sopenharmony_ci "error byte at " 41062306a36Sopenharmony_ci "read byte %d " 41162306a36Sopenharmony_ci "of 0x%x [%s].\n", 41262306a36Sopenharmony_ci i, cmd, 41362306a36Sopenharmony_ci wfcmd->action); 41462306a36Sopenharmony_ci return 1; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Can you believe this madness ? */ 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (c == 1 && 42062306a36Sopenharmony_ci wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { 42162306a36Sopenharmony_ci rbuf[0] = WF_ST_EMPTY; 42262306a36Sopenharmony_ci return (0); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci } else if (c == 3 && 42562306a36Sopenharmony_ci wfcmd->cmd == WFC_UPLOAD_PATCH) { 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 3; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci } else if (c == 1 && 43062306a36Sopenharmony_ci wfcmd->cmd == WFC_UPLOAD_PROGRAM) { 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return 1; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci DPRINT (WF_DEBUG_IO, "error %d (%s) " 43762306a36Sopenharmony_ci "during " 43862306a36Sopenharmony_ci "read for byte " 43962306a36Sopenharmony_ci "%d of 0x%x " 44062306a36Sopenharmony_ci "[%s].\n", 44162306a36Sopenharmony_ci c, 44262306a36Sopenharmony_ci wavefront_errorstr (c), 44362306a36Sopenharmony_ci i, cmd, 44462306a36Sopenharmony_ci wfcmd->action); 44562306a36Sopenharmony_ci return 1; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci } else { 45062306a36Sopenharmony_ci rbuf[i] = c; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* Some commands need an ACK, but return zero instead 46262306a36Sopenharmony_ci of the standard value. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci ack = wavefront_read(dev); 46662306a36Sopenharmony_ci if (ack == 0) 46762306a36Sopenharmony_ci ack = WF_ACK; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (ack != WF_ACK) { 47062306a36Sopenharmony_ci if (ack == -1) { 47162306a36Sopenharmony_ci DPRINT (WF_DEBUG_IO, "cannot read ack for " 47262306a36Sopenharmony_ci "0x%x [%s].\n", 47362306a36Sopenharmony_ci cmd, wfcmd->action); 47462306a36Sopenharmony_ci return 1; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci } else { 47762306a36Sopenharmony_ci int err = -1; /* something unknown */ 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (ack == 0xff) { /* explicit error */ 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci err = wavefront_read(dev); 48262306a36Sopenharmony_ci if (err == -1) { 48362306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, 48462306a36Sopenharmony_ci "cannot read err " 48562306a36Sopenharmony_ci "for 0x%x [%s].\n", 48662306a36Sopenharmony_ci cmd, wfcmd->action); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci DPRINT (WF_DEBUG_IO, "0x%x [%s] " 49162306a36Sopenharmony_ci "failed (0x%x, 0x%x, %s)\n", 49262306a36Sopenharmony_ci cmd, wfcmd->action, ack, err, 49362306a36Sopenharmony_ci wavefront_errorstr (err)); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return -err; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "ack received " 50062306a36Sopenharmony_ci "for 0x%x [%s]\n", 50162306a36Sopenharmony_ci cmd, wfcmd->action); 50262306a36Sopenharmony_ci } else { 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need " 50562306a36Sopenharmony_ci "ACK (%d,%d,%d)\n", 50662306a36Sopenharmony_ci cmd, wfcmd->action, wfcmd->read_cnt, 50762306a36Sopenharmony_ci wfcmd->write_cnt, wfcmd->need_ack); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci} 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci/*********************************************************************** 51562306a36Sopenharmony_ciWaveFront data munging 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ciThings here are weird. All data written to the board cannot 51862306a36Sopenharmony_cihave its most significant bit set. Any data item with values 51962306a36Sopenharmony_cipotentially > 0x7F (127) must be split across multiple bytes. 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ciSometimes, we need to munge numeric values that are represented on 52262306a36Sopenharmony_cithe x86 side as 8-32 bit values. Sometimes, we need to munge data 52362306a36Sopenharmony_cithat is represented on the x86 side as an array of bytes. The most 52462306a36Sopenharmony_ciefficient approach to handling both cases seems to be to use 2 52562306a36Sopenharmony_cidifferent functions for munging and 2 for de-munging. This avoids 52662306a36Sopenharmony_ciweird casting and worrying about bit-level offsets. 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci**********************************************************************/ 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic unsigned char * 53162306a36Sopenharmony_cimunge_int32 (unsigned int src, 53262306a36Sopenharmony_ci unsigned char *dst, 53362306a36Sopenharmony_ci unsigned int dst_size) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci unsigned int i; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci for (i = 0; i < dst_size; i++) { 53862306a36Sopenharmony_ci *dst = src & 0x7F; /* Mask high bit of LSB */ 53962306a36Sopenharmony_ci src = src >> 7; /* Rotate Right 7 bits */ 54062306a36Sopenharmony_ci /* Note: we leave the upper bits in place */ 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci dst++; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci return dst; 54562306a36Sopenharmony_ci}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int 54862306a36Sopenharmony_cidemunge_int32 (unsigned char* src, int src_size) 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci int i; 55262306a36Sopenharmony_ci int outval = 0; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci for (i = src_size - 1; i >= 0; i--) { 55562306a36Sopenharmony_ci outval=(outval<<7)+src[i]; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return outval; 55962306a36Sopenharmony_ci}; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic 56262306a36Sopenharmony_ciunsigned char * 56362306a36Sopenharmony_cimunge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size) 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci unsigned int i; 56762306a36Sopenharmony_ci unsigned int last = dst_size / 2; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci for (i = 0; i < last; i++) { 57062306a36Sopenharmony_ci *dst++ = src[i] & 0x7f; 57162306a36Sopenharmony_ci *dst++ = src[i] >> 7; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci return dst; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic 57762306a36Sopenharmony_ciunsigned char * 57862306a36Sopenharmony_cidemunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci int i; 58262306a36Sopenharmony_ci unsigned char *end = src + src_bytes; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* NOTE: src and dst *CAN* point to the same address */ 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci for (i = 0; src != end; i++) { 58762306a36Sopenharmony_ci dst[i] = *src++; 58862306a36Sopenharmony_ci dst[i] |= (*src++)<<7; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return dst; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci/*********************************************************************** 59562306a36Sopenharmony_ciWaveFront: sample, patch and program management. 59662306a36Sopenharmony_ci***********************************************************************/ 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int 59962306a36Sopenharmony_ciwavefront_delete_sample (snd_wavefront_t *dev, int sample_num) 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci unsigned char wbuf[2]; 60362306a36Sopenharmony_ci int x; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci wbuf[0] = sample_num & 0x7f; 60662306a36Sopenharmony_ci wbuf[1] = sample_num >> 7; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci x = snd_wavefront_cmd(dev, WFC_DELETE_SAMPLE, NULL, wbuf); 60962306a36Sopenharmony_ci if (!x) 61062306a36Sopenharmony_ci dev->sample_status[sample_num] = WF_ST_EMPTY; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci return x; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_cistatic int 61662306a36Sopenharmony_ciwavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom) 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci int i; 62062306a36Sopenharmony_ci unsigned char rbuf[32], wbuf[32]; 62162306a36Sopenharmony_ci unsigned int sc_real, sc_alias, sc_multi; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* check sample status */ 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_GET_NSAMPLES, rbuf, wbuf)) { 62662306a36Sopenharmony_ci snd_printk ("cannot request sample count.\n"); 62762306a36Sopenharmony_ci return -1; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci sc_real = sc_alias = sc_multi = dev->samples_used = 0; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci for (i = 0; i < WF_MAX_SAMPLE; i++) { 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci wbuf[0] = i & 0x7f; 63562306a36Sopenharmony_ci wbuf[1] = i >> 7; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { 63862306a36Sopenharmony_ci snd_printk(KERN_WARNING "cannot identify sample " 63962306a36Sopenharmony_ci "type of slot %d\n", i); 64062306a36Sopenharmony_ci dev->sample_status[i] = WF_ST_EMPTY; 64162306a36Sopenharmony_ci continue; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci dev->sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (assume_rom) { 64762306a36Sopenharmony_ci dev->sample_status[i] |= WF_SLOT_ROM; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci switch (rbuf[0] & WF_ST_MASK) { 65162306a36Sopenharmony_ci case WF_ST_SAMPLE: 65262306a36Sopenharmony_ci sc_real++; 65362306a36Sopenharmony_ci break; 65462306a36Sopenharmony_ci case WF_ST_MULTISAMPLE: 65562306a36Sopenharmony_ci sc_multi++; 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci case WF_ST_ALIAS: 65862306a36Sopenharmony_ci sc_alias++; 65962306a36Sopenharmony_ci break; 66062306a36Sopenharmony_ci case WF_ST_EMPTY: 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci default: 66462306a36Sopenharmony_ci snd_printk ("unknown sample type for " 66562306a36Sopenharmony_ci "slot %d (0x%x)\n", 66662306a36Sopenharmony_ci i, rbuf[0]); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (rbuf[0] != WF_ST_EMPTY) { 67062306a36Sopenharmony_ci dev->samples_used++; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci snd_printk ("%d samples used (%d real, %d aliases, %d multi), " 67562306a36Sopenharmony_ci "%d empty\n", dev->samples_used, sc_real, sc_alias, sc_multi, 67662306a36Sopenharmony_ci WF_MAX_SAMPLE - dev->samples_used); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return (0); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int 68462306a36Sopenharmony_ciwavefront_get_patch_status (snd_wavefront_t *dev) 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci{ 68762306a36Sopenharmony_ci unsigned char patchbuf[WF_PATCH_BYTES]; 68862306a36Sopenharmony_ci unsigned char patchnum[2]; 68962306a36Sopenharmony_ci wavefront_patch *p; 69062306a36Sopenharmony_ci int i, x, cnt, cnt2; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci for (i = 0; i < WF_MAX_PATCH; i++) { 69362306a36Sopenharmony_ci patchnum[0] = i & 0x7f; 69462306a36Sopenharmony_ci patchnum[1] = i >> 7; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci x = snd_wavefront_cmd(dev, WFC_UPLOAD_PATCH, patchbuf, 69762306a36Sopenharmony_ci patchnum); 69862306a36Sopenharmony_ci if (x == 0) { 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci dev->patch_status[i] |= WF_SLOT_FILLED; 70162306a36Sopenharmony_ci p = (wavefront_patch *) patchbuf; 70262306a36Sopenharmony_ci dev->sample_status 70362306a36Sopenharmony_ci [p->sample_number|(p->sample_msb<<7)] |= 70462306a36Sopenharmony_ci WF_SLOT_USED; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci } else if (x == 3) { /* Bad patch number */ 70762306a36Sopenharmony_ci dev->patch_status[i] = 0; 70862306a36Sopenharmony_ci } else { 70962306a36Sopenharmony_ci snd_printk ("upload patch " 71062306a36Sopenharmony_ci "error 0x%x\n", x); 71162306a36Sopenharmony_ci dev->patch_status[i] = 0; 71262306a36Sopenharmony_ci return 1; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci /* program status has already filled in slot_used bits */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { 71962306a36Sopenharmony_ci if (dev->patch_status[i] & WF_SLOT_FILLED) { 72062306a36Sopenharmony_ci cnt++; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci if (dev->patch_status[i] & WF_SLOT_USED) { 72362306a36Sopenharmony_ci cnt2++; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci snd_printk ("%d patch slots filled, %d in use\n", cnt, cnt2); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci return (0); 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic int 73362306a36Sopenharmony_ciwavefront_get_program_status (snd_wavefront_t *dev) 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci unsigned char progbuf[WF_PROGRAM_BYTES]; 73762306a36Sopenharmony_ci wavefront_program prog; 73862306a36Sopenharmony_ci unsigned char prognum; 73962306a36Sopenharmony_ci int i, x, l, cnt; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci for (i = 0; i < WF_MAX_PROGRAM; i++) { 74262306a36Sopenharmony_ci prognum = i; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci x = snd_wavefront_cmd(dev, WFC_UPLOAD_PROGRAM, progbuf, 74562306a36Sopenharmony_ci &prognum); 74662306a36Sopenharmony_ci if (x == 0) { 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci dev->prog_status[i] |= WF_SLOT_USED; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci demunge_buf (progbuf, (unsigned char *) &prog, 75162306a36Sopenharmony_ci WF_PROGRAM_BYTES); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci for (l = 0; l < WF_NUM_LAYERS; l++) { 75462306a36Sopenharmony_ci if (prog.layer[l].mute) { 75562306a36Sopenharmony_ci dev->patch_status 75662306a36Sopenharmony_ci [prog.layer[l].patch_number] |= 75762306a36Sopenharmony_ci WF_SLOT_USED; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci } else if (x == 1) { /* Bad program number */ 76162306a36Sopenharmony_ci dev->prog_status[i] = 0; 76262306a36Sopenharmony_ci } else { 76362306a36Sopenharmony_ci snd_printk ("upload program " 76462306a36Sopenharmony_ci "error 0x%x\n", x); 76562306a36Sopenharmony_ci dev->prog_status[i] = 0; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { 77062306a36Sopenharmony_ci if (dev->prog_status[i]) { 77162306a36Sopenharmony_ci cnt++; 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci snd_printk ("%d programs slots in use\n", cnt); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci return (0); 77862306a36Sopenharmony_ci} 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_cistatic int 78162306a36Sopenharmony_ciwavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header) 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci unsigned char buf[WF_PATCH_BYTES+2]; 78562306a36Sopenharmony_ci unsigned char *bptr; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", 78862306a36Sopenharmony_ci header->number); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (header->number >= ARRAY_SIZE(dev->patch_status)) 79162306a36Sopenharmony_ci return -EINVAL; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci dev->patch_status[header->number] |= WF_SLOT_FILLED; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci bptr = munge_int32 (header->number, buf, 2); 79662306a36Sopenharmony_ci munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) { 79962306a36Sopenharmony_ci snd_printk ("download patch failed\n"); 80062306a36Sopenharmony_ci return -EIO; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return (0); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int 80762306a36Sopenharmony_ciwavefront_send_program (snd_wavefront_t *dev, wavefront_patch_info *header) 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci{ 81062306a36Sopenharmony_ci unsigned char buf[WF_PROGRAM_BYTES+1]; 81162306a36Sopenharmony_ci int i; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", 81462306a36Sopenharmony_ci header->number); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (header->number >= ARRAY_SIZE(dev->prog_status)) 81762306a36Sopenharmony_ci return -EINVAL; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci dev->prog_status[header->number] = WF_SLOT_USED; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* XXX need to zero existing SLOT_USED bit for program_status[i] 82262306a36Sopenharmony_ci where `i' is the program that's being (potentially) overwritten. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci for (i = 0; i < WF_NUM_LAYERS; i++) { 82662306a36Sopenharmony_ci if (header->hdr.pr.layer[i].mute) { 82762306a36Sopenharmony_ci dev->patch_status[header->hdr.pr.layer[i].patch_number] |= 82862306a36Sopenharmony_ci WF_SLOT_USED; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* XXX need to mark SLOT_USED for sample used by 83162306a36Sopenharmony_ci patch_number, but this means we have to load it. Ick. 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci buf[0] = header->number; 83762306a36Sopenharmony_ci munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) { 84062306a36Sopenharmony_ci snd_printk ("download patch failed\n"); 84162306a36Sopenharmony_ci return -EIO; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return (0); 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_cistatic int 84862306a36Sopenharmony_ciwavefront_freemem (snd_wavefront_t *dev) 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci char rbuf[8]; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { 85462306a36Sopenharmony_ci snd_printk ("can't get memory stats.\n"); 85562306a36Sopenharmony_ci return -1; 85662306a36Sopenharmony_ci } else { 85762306a36Sopenharmony_ci return demunge_int32 (rbuf, 4); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic int 86262306a36Sopenharmony_ciwavefront_send_sample (snd_wavefront_t *dev, 86362306a36Sopenharmony_ci wavefront_patch_info *header, 86462306a36Sopenharmony_ci u16 __user *dataptr, 86562306a36Sopenharmony_ci int data_is_unsigned) 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci /* samples are downloaded via a 16-bit wide i/o port 86962306a36Sopenharmony_ci (you could think of it as 2 adjacent 8-bit wide ports 87062306a36Sopenharmony_ci but its less efficient that way). therefore, all 87162306a36Sopenharmony_ci the blocksizes and so forth listed in the documentation, 87262306a36Sopenharmony_ci and used conventionally to refer to sample sizes, 87362306a36Sopenharmony_ci which are given in 8-bit units (bytes), need to be 87462306a36Sopenharmony_ci divided by 2. 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci u16 sample_short = 0; 87862306a36Sopenharmony_ci u32 length; 87962306a36Sopenharmony_ci u16 __user *data_end = NULL; 88062306a36Sopenharmony_ci unsigned int i; 88162306a36Sopenharmony_ci const unsigned int max_blksize = 4096/2; 88262306a36Sopenharmony_ci unsigned int written; 88362306a36Sopenharmony_ci unsigned int blocksize; 88462306a36Sopenharmony_ci int dma_ack; 88562306a36Sopenharmony_ci int blocknum; 88662306a36Sopenharmony_ci unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; 88762306a36Sopenharmony_ci unsigned char *shptr; 88862306a36Sopenharmony_ci int skip = 0; 88962306a36Sopenharmony_ci int initial_skip = 0; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " 89262306a36Sopenharmony_ci "type %d, %d bytes from 0x%lx\n", 89362306a36Sopenharmony_ci header->size ? "" : "header ", 89462306a36Sopenharmony_ci header->number, header->subkey, 89562306a36Sopenharmony_ci header->size, 89662306a36Sopenharmony_ci (unsigned long) header->dataptr); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { 89962306a36Sopenharmony_ci int x; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci x = wavefront_find_free_sample(dev); 90262306a36Sopenharmony_ci if (x < 0) 90362306a36Sopenharmony_ci return -ENOMEM; 90462306a36Sopenharmony_ci snd_printk ("unspecified sample => %d\n", x); 90562306a36Sopenharmony_ci header->number = x; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (header->number >= WF_MAX_SAMPLE) 90962306a36Sopenharmony_ci return -EINVAL; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci if (header->size) { 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* XXX it's a debatable point whether or not RDONLY semantics 91462306a36Sopenharmony_ci on the ROM samples should cover just the sample data or 91562306a36Sopenharmony_ci the sample header. For now, it only covers the sample data, 91662306a36Sopenharmony_ci so anyone is free at all times to rewrite sample headers. 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci My reason for this is that we have the sample headers 91962306a36Sopenharmony_ci available in the WFB file for General MIDI, and so these 92062306a36Sopenharmony_ci can always be reset if needed. The sample data, however, 92162306a36Sopenharmony_ci cannot be recovered without a complete reset and firmware 92262306a36Sopenharmony_ci reload of the ICS2115, which is a very expensive operation. 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci So, doing things this way allows us to honor the notion of 92562306a36Sopenharmony_ci "RESETSAMPLES" reasonably cheaply. Note however, that this 92662306a36Sopenharmony_ci is done purely at user level: there is no WFB parser in 92762306a36Sopenharmony_ci this driver, and so a complete reset (back to General MIDI, 92862306a36Sopenharmony_ci or theoretically some other configuration) is the 92962306a36Sopenharmony_ci responsibility of the user level library. 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci To try to do this in the kernel would be a little 93262306a36Sopenharmony_ci crazy: we'd need 158K of kernel space just to hold 93362306a36Sopenharmony_ci a copy of the patch/program/sample header data. 93462306a36Sopenharmony_ci */ 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (dev->rom_samples_rdonly) { 93762306a36Sopenharmony_ci if (dev->sample_status[header->number] & WF_SLOT_ROM) { 93862306a36Sopenharmony_ci snd_printk ("sample slot %d " 93962306a36Sopenharmony_ci "write protected\n", 94062306a36Sopenharmony_ci header->number); 94162306a36Sopenharmony_ci return -EACCES; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci wavefront_delete_sample (dev, header->number); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (header->size) { 94962306a36Sopenharmony_ci dev->freemem = wavefront_freemem (dev); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (dev->freemem < (int)header->size) { 95262306a36Sopenharmony_ci snd_printk ("insufficient memory to " 95362306a36Sopenharmony_ci "load %d byte sample.\n", 95462306a36Sopenharmony_ci header->size); 95562306a36Sopenharmony_ci return -ENOMEM; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci skip = WF_GET_CHANNEL(&header->hdr.s); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { 96362306a36Sopenharmony_ci snd_printk ("channel selection only " 96462306a36Sopenharmony_ci "possible on 16-bit samples"); 96562306a36Sopenharmony_ci return -EINVAL; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci switch (skip) { 96962306a36Sopenharmony_ci case 0: 97062306a36Sopenharmony_ci initial_skip = 0; 97162306a36Sopenharmony_ci skip = 1; 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci case 1: 97462306a36Sopenharmony_ci initial_skip = 0; 97562306a36Sopenharmony_ci skip = 2; 97662306a36Sopenharmony_ci break; 97762306a36Sopenharmony_ci case 2: 97862306a36Sopenharmony_ci initial_skip = 1; 97962306a36Sopenharmony_ci skip = 2; 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci case 3: 98262306a36Sopenharmony_ci initial_skip = 2; 98362306a36Sopenharmony_ci skip = 3; 98462306a36Sopenharmony_ci break; 98562306a36Sopenharmony_ci case 4: 98662306a36Sopenharmony_ci initial_skip = 3; 98762306a36Sopenharmony_ci skip = 4; 98862306a36Sopenharmony_ci break; 98962306a36Sopenharmony_ci case 5: 99062306a36Sopenharmony_ci initial_skip = 4; 99162306a36Sopenharmony_ci skip = 5; 99262306a36Sopenharmony_ci break; 99362306a36Sopenharmony_ci case 6: 99462306a36Sopenharmony_ci initial_skip = 5; 99562306a36Sopenharmony_ci skip = 6; 99662306a36Sopenharmony_ci break; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " 100062306a36Sopenharmony_ci "initial skip = %d, skip = %d\n", 100162306a36Sopenharmony_ci WF_GET_CHANNEL (&header->hdr.s), 100262306a36Sopenharmony_ci initial_skip, skip); 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* Be safe, and zero the "Unused" bits ... */ 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci WF_SET_CHANNEL(&header->hdr.s, 0); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* adjust size for 16 bit samples by dividing by two. We always 100962306a36Sopenharmony_ci send 16 bits per write, even for 8 bit samples, so the length 101062306a36Sopenharmony_ci is always half the size of the sample data in bytes. 101162306a36Sopenharmony_ci */ 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci length = header->size / 2; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* the data we're sent has not been munged, and in fact, the 101662306a36Sopenharmony_ci header we have to send isn't just a munged copy either. 101762306a36Sopenharmony_ci so, build the sample header right here. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci shptr = &sample_hdr[0]; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci shptr = munge_int32 (header->number, shptr, 2); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (header->size) { 102562306a36Sopenharmony_ci shptr = munge_int32 (length, shptr, 4); 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci /* Yes, a 4 byte result doesn't contain all of the offset bits, 102962306a36Sopenharmony_ci but the offset only uses 24 bits. 103062306a36Sopenharmony_ci */ 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleStartOffset), 103362306a36Sopenharmony_ci shptr, 4); 103462306a36Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.loopStartOffset), 103562306a36Sopenharmony_ci shptr, 4); 103662306a36Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.loopEndOffset), 103762306a36Sopenharmony_ci shptr, 4); 103862306a36Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleEndOffset), 103962306a36Sopenharmony_ci shptr, 4); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* This one is truly weird. What kind of weirdo decided that in 104262306a36Sopenharmony_ci a system dominated by 16 and 32 bit integers, they would use 104362306a36Sopenharmony_ci a just 12 bits ? 104462306a36Sopenharmony_ci */ 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci /* Why is this nybblified, when the MSB is *always* zero ? 104962306a36Sopenharmony_ci Anyway, we can't take address of bitfield, so make a 105062306a36Sopenharmony_ci good-faith guess at where it starts. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), 105462306a36Sopenharmony_ci shptr, 2); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, 105762306a36Sopenharmony_ci header->size ? 105862306a36Sopenharmony_ci WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, 105962306a36Sopenharmony_ci NULL, sample_hdr)) { 106062306a36Sopenharmony_ci snd_printk ("sample %sdownload refused.\n", 106162306a36Sopenharmony_ci header->size ? "" : "header "); 106262306a36Sopenharmony_ci return -EIO; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci if (header->size == 0) { 106662306a36Sopenharmony_ci goto sent; /* Sorry. Just had to have one somewhere */ 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci data_end = dataptr + length; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* Do any initial skip over an unused channel's data */ 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci dataptr += initial_skip; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci for (written = 0, blocknum = 0; 107662306a36Sopenharmony_ci written < length; written += max_blksize, blocknum++) { 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if ((length - written) > max_blksize) { 107962306a36Sopenharmony_ci blocksize = max_blksize; 108062306a36Sopenharmony_ci } else { 108162306a36Sopenharmony_ci /* round to nearest 16-byte value */ 108262306a36Sopenharmony_ci blocksize = ALIGN(length - written, 8); 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) { 108662306a36Sopenharmony_ci snd_printk ("download block " 108762306a36Sopenharmony_ci "request refused.\n"); 108862306a36Sopenharmony_ci return -EIO; 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci for (i = 0; i < blocksize; i++) { 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (dataptr < data_end) { 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (get_user(sample_short, dataptr)) 109662306a36Sopenharmony_ci return -EFAULT; 109762306a36Sopenharmony_ci dataptr += skip; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci if (data_is_unsigned) { /* GUS ? */ 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci /* 8 bit sample 110462306a36Sopenharmony_ci resolution, sign 110562306a36Sopenharmony_ci extend both bytes. 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci ((unsigned char*) 110962306a36Sopenharmony_ci &sample_short)[0] += 0x7f; 111062306a36Sopenharmony_ci ((unsigned char*) 111162306a36Sopenharmony_ci &sample_short)[1] += 0x7f; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci } else { 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* 16 bit sample 111662306a36Sopenharmony_ci resolution, sign 111762306a36Sopenharmony_ci extend the MSB. 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci sample_short += 0x7fff; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci } else { 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci /* In padding section of final block: 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci Don't fetch unsupplied data from 112962306a36Sopenharmony_ci user space, just continue with 113062306a36Sopenharmony_ci whatever the final value was. 113162306a36Sopenharmony_ci */ 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (i < blocksize - 1) { 113562306a36Sopenharmony_ci outw (sample_short, dev->block_port); 113662306a36Sopenharmony_ci } else { 113762306a36Sopenharmony_ci outw (sample_short, dev->last_block_port); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* Get "DMA page acknowledge", even though its really 114262306a36Sopenharmony_ci nothing to do with DMA at all. 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci dma_ack = wavefront_read(dev); 114662306a36Sopenharmony_ci if (dma_ack != WF_DMA_ACK) { 114762306a36Sopenharmony_ci if (dma_ack == -1) { 114862306a36Sopenharmony_ci snd_printk ("upload sample " 114962306a36Sopenharmony_ci "DMA ack timeout\n"); 115062306a36Sopenharmony_ci return -EIO; 115162306a36Sopenharmony_ci } else { 115262306a36Sopenharmony_ci snd_printk ("upload sample " 115362306a36Sopenharmony_ci "DMA ack error 0x%x\n", 115462306a36Sopenharmony_ci dma_ack); 115562306a36Sopenharmony_ci return -EIO; 115662306a36Sopenharmony_ci } 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci /* Note, label is here because sending the sample header shouldn't 116362306a36Sopenharmony_ci alter the sample_status info at all. 116462306a36Sopenharmony_ci */ 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci sent: 116762306a36Sopenharmony_ci return (0); 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int 117162306a36Sopenharmony_ciwavefront_send_alias (snd_wavefront_t *dev, wavefront_patch_info *header) 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci unsigned char alias_hdr[WF_ALIAS_BYTES]; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is " 117762306a36Sopenharmony_ci "alias for %d\n", 117862306a36Sopenharmony_ci header->number, 117962306a36Sopenharmony_ci header->hdr.a.OriginalSample); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (header->number >= WF_MAX_SAMPLE) 118262306a36Sopenharmony_ci return -EINVAL; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci munge_int32 (header->number, &alias_hdr[0], 2); 118562306a36Sopenharmony_ci munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); 118662306a36Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset), 118762306a36Sopenharmony_ci &alias_hdr[4], 4); 118862306a36Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset), 118962306a36Sopenharmony_ci &alias_hdr[8], 4); 119062306a36Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset), 119162306a36Sopenharmony_ci &alias_hdr[12], 4); 119262306a36Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset), 119362306a36Sopenharmony_ci &alias_hdr[16], 4); 119462306a36Sopenharmony_ci munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3); 119562306a36Sopenharmony_ci munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { 119862306a36Sopenharmony_ci snd_printk ("download alias failed.\n"); 119962306a36Sopenharmony_ci return -EIO; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci return (0); 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic int 120862306a36Sopenharmony_ciwavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci int i; 121162306a36Sopenharmony_ci int num_samples; 121262306a36Sopenharmony_ci unsigned char *msample_hdr; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci if (header->number >= WF_MAX_SAMPLE) 121562306a36Sopenharmony_ci return -EINVAL; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci msample_hdr = kmalloc(WF_MSAMPLE_BYTES, GFP_KERNEL); 121862306a36Sopenharmony_ci if (! msample_hdr) 121962306a36Sopenharmony_ci return -ENOMEM; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci munge_int32 (header->number, &msample_hdr[0], 2); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci /* You'll recall at this point that the "number of samples" value 122462306a36Sopenharmony_ci in a wavefront_multisample struct is actually the log2 of the 122562306a36Sopenharmony_ci real number of samples. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); 122962306a36Sopenharmony_ci msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n", 123262306a36Sopenharmony_ci header->number, 123362306a36Sopenharmony_ci header->hdr.ms.NumberOfSamples, 123462306a36Sopenharmony_ci num_samples); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci for (i = 0; i < num_samples; i++) { 123762306a36Sopenharmony_ci DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n", 123862306a36Sopenharmony_ci i, header->hdr.ms.SampleNumber[i]); 123962306a36Sopenharmony_ci munge_int32 (header->hdr.ms.SampleNumber[i], 124062306a36Sopenharmony_ci &msample_hdr[3+(i*2)], 2); 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* Need a hack here to pass in the number of bytes 124462306a36Sopenharmony_ci to be written to the synth. This is ugly, and perhaps 124562306a36Sopenharmony_ci one day, I'll fix it. 124662306a36Sopenharmony_ci */ 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE, 124962306a36Sopenharmony_ci (unsigned char *) (long) ((num_samples*2)+3), 125062306a36Sopenharmony_ci msample_hdr)) { 125162306a36Sopenharmony_ci snd_printk ("download of multisample failed.\n"); 125262306a36Sopenharmony_ci kfree(msample_hdr); 125362306a36Sopenharmony_ci return -EIO; 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci kfree(msample_hdr); 125962306a36Sopenharmony_ci return (0); 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic int 126362306a36Sopenharmony_ciwavefront_fetch_multisample (snd_wavefront_t *dev, 126462306a36Sopenharmony_ci wavefront_patch_info *header) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci int i; 126762306a36Sopenharmony_ci unsigned char log_ns[1]; 126862306a36Sopenharmony_ci unsigned char number[2]; 126962306a36Sopenharmony_ci int num_samples; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci munge_int32 (header->number, number, 2); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { 127462306a36Sopenharmony_ci snd_printk ("upload multisample failed.\n"); 127562306a36Sopenharmony_ci return -EIO; 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n", 127962306a36Sopenharmony_ci header->number, log_ns[0]); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci header->hdr.ms.NumberOfSamples = log_ns[0]; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci /* get the number of samples ... */ 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci num_samples = (1 << log_ns[0]); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci for (i = 0; i < num_samples; i++) { 128862306a36Sopenharmony_ci char d[2]; 128962306a36Sopenharmony_ci int val; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci val = wavefront_read(dev); 129262306a36Sopenharmony_ci if (val == -1) { 129362306a36Sopenharmony_ci snd_printk ("upload multisample failed " 129462306a36Sopenharmony_ci "during sample loop.\n"); 129562306a36Sopenharmony_ci return -EIO; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci d[0] = val; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci val = wavefront_read(dev); 130062306a36Sopenharmony_ci if (val == -1) { 130162306a36Sopenharmony_ci snd_printk ("upload multisample failed " 130262306a36Sopenharmony_ci "during sample loop.\n"); 130362306a36Sopenharmony_ci return -EIO; 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci d[1] = val; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci header->hdr.ms.SampleNumber[i] = 130862306a36Sopenharmony_ci demunge_int32 ((unsigned char *) d, 2); 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n", 131162306a36Sopenharmony_ci i, header->hdr.ms.SampleNumber[i]); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return (0); 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic int 131962306a36Sopenharmony_ciwavefront_send_drum (snd_wavefront_t *dev, wavefront_patch_info *header) 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci unsigned char drumbuf[WF_DRUM_BYTES]; 132362306a36Sopenharmony_ci wavefront_drum *drum = &header->hdr.d; 132462306a36Sopenharmony_ci int i; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI " 132762306a36Sopenharmony_ci "note %d, patch = %d\n", 132862306a36Sopenharmony_ci header->number, drum->PatchNumber); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci drumbuf[0] = header->number & 0x7f; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 133362306a36Sopenharmony_ci munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2); 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { 133762306a36Sopenharmony_ci snd_printk ("download drum failed.\n"); 133862306a36Sopenharmony_ci return -EIO; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci return (0); 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic int 134562306a36Sopenharmony_ciwavefront_find_free_sample (snd_wavefront_t *dev) 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci{ 134862306a36Sopenharmony_ci int i; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci for (i = 0; i < WF_MAX_SAMPLE; i++) { 135162306a36Sopenharmony_ci if (!(dev->sample_status[i] & WF_SLOT_FILLED)) { 135262306a36Sopenharmony_ci return i; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci snd_printk ("no free sample slots!\n"); 135662306a36Sopenharmony_ci return -1; 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci#if 0 136062306a36Sopenharmony_cistatic int 136162306a36Sopenharmony_ciwavefront_find_free_patch (snd_wavefront_t *dev) 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci int i; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci for (i = 0; i < WF_MAX_PATCH; i++) { 136762306a36Sopenharmony_ci if (!(dev->patch_status[i] & WF_SLOT_FILLED)) { 136862306a36Sopenharmony_ci return i; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci snd_printk ("no free patch slots!\n"); 137262306a36Sopenharmony_ci return -1; 137362306a36Sopenharmony_ci} 137462306a36Sopenharmony_ci#endif 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic int 137762306a36Sopenharmony_ciwavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci wavefront_patch_info *header; 138062306a36Sopenharmony_ci int err; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci header = kmalloc(sizeof(*header), GFP_KERNEL); 138362306a36Sopenharmony_ci if (! header) 138462306a36Sopenharmony_ci return -ENOMEM; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci if (copy_from_user (header, addr, sizeof(wavefront_patch_info) - 138762306a36Sopenharmony_ci sizeof(wavefront_any))) { 138862306a36Sopenharmony_ci snd_printk ("bad address for load patch.\n"); 138962306a36Sopenharmony_ci err = -EFAULT; 139062306a36Sopenharmony_ci goto __error; 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "download " 139462306a36Sopenharmony_ci "Sample type: %d " 139562306a36Sopenharmony_ci "Sample number: %d " 139662306a36Sopenharmony_ci "Sample size: %d\n", 139762306a36Sopenharmony_ci header->subkey, 139862306a36Sopenharmony_ci header->number, 139962306a36Sopenharmony_ci header->size); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci switch (header->subkey) { 140262306a36Sopenharmony_ci case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (copy_from_user (&header->hdr.s, header->hdrptr, 140562306a36Sopenharmony_ci sizeof (wavefront_sample))) { 140662306a36Sopenharmony_ci err = -EFAULT; 140762306a36Sopenharmony_ci break; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci err = wavefront_send_sample (dev, header, header->dataptr, 0); 141162306a36Sopenharmony_ci break; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci case WF_ST_MULTISAMPLE: 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci if (copy_from_user (&header->hdr.s, header->hdrptr, 141662306a36Sopenharmony_ci sizeof (wavefront_multisample))) { 141762306a36Sopenharmony_ci err = -EFAULT; 141862306a36Sopenharmony_ci break; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci err = wavefront_send_multisample (dev, header); 142262306a36Sopenharmony_ci break; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci case WF_ST_ALIAS: 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if (copy_from_user (&header->hdr.a, header->hdrptr, 142762306a36Sopenharmony_ci sizeof (wavefront_alias))) { 142862306a36Sopenharmony_ci err = -EFAULT; 142962306a36Sopenharmony_ci break; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci err = wavefront_send_alias (dev, header); 143362306a36Sopenharmony_ci break; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci case WF_ST_DRUM: 143662306a36Sopenharmony_ci if (copy_from_user (&header->hdr.d, header->hdrptr, 143762306a36Sopenharmony_ci sizeof (wavefront_drum))) { 143862306a36Sopenharmony_ci err = -EFAULT; 143962306a36Sopenharmony_ci break; 144062306a36Sopenharmony_ci } 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci err = wavefront_send_drum (dev, header); 144362306a36Sopenharmony_ci break; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci case WF_ST_PATCH: 144662306a36Sopenharmony_ci if (copy_from_user (&header->hdr.p, header->hdrptr, 144762306a36Sopenharmony_ci sizeof (wavefront_patch))) { 144862306a36Sopenharmony_ci err = -EFAULT; 144962306a36Sopenharmony_ci break; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci err = wavefront_send_patch (dev, header); 145362306a36Sopenharmony_ci break; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci case WF_ST_PROGRAM: 145662306a36Sopenharmony_ci if (copy_from_user (&header->hdr.pr, header->hdrptr, 145762306a36Sopenharmony_ci sizeof (wavefront_program))) { 145862306a36Sopenharmony_ci err = -EFAULT; 145962306a36Sopenharmony_ci break; 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci err = wavefront_send_program (dev, header); 146362306a36Sopenharmony_ci break; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci default: 146662306a36Sopenharmony_ci snd_printk ("unknown patch type %d.\n", 146762306a36Sopenharmony_ci header->subkey); 146862306a36Sopenharmony_ci err = -EINVAL; 146962306a36Sopenharmony_ci break; 147062306a36Sopenharmony_ci } 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci __error: 147362306a36Sopenharmony_ci kfree(header); 147462306a36Sopenharmony_ci return err; 147562306a36Sopenharmony_ci} 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci/*********************************************************************** 147862306a36Sopenharmony_ciWaveFront: hardware-dependent interface 147962306a36Sopenharmony_ci***********************************************************************/ 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic void 148262306a36Sopenharmony_ciprocess_sample_hdr (u8 *buf) 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci wavefront_sample s; 148662306a36Sopenharmony_ci u8 *ptr; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci ptr = buf; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci /* The board doesn't send us an exact copy of a "wavefront_sample" 149162306a36Sopenharmony_ci in response to an Upload Sample Header command. Instead, we 149262306a36Sopenharmony_ci have to convert the data format back into our data structure, 149362306a36Sopenharmony_ci just as in the Download Sample command, where we have to do 149462306a36Sopenharmony_ci something very similar in the reverse direction. 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci *((u32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; 149862306a36Sopenharmony_ci *((u32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; 149962306a36Sopenharmony_ci *((u32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; 150062306a36Sopenharmony_ci *((u32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; 150162306a36Sopenharmony_ci *((u32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci s.SampleResolution = *ptr & 0x3; 150462306a36Sopenharmony_ci s.Loop = *ptr & 0x8; 150562306a36Sopenharmony_ci s.Bidirectional = *ptr & 0x10; 150662306a36Sopenharmony_ci s.Reverse = *ptr & 0x40; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* Now copy it back to where it came from */ 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample)); 151162306a36Sopenharmony_ci} 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_cistatic int 151462306a36Sopenharmony_ciwavefront_synth_control (snd_wavefront_card_t *acard, 151562306a36Sopenharmony_ci wavefront_control *wc) 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci snd_wavefront_t *dev = &acard->wavefront; 151962306a36Sopenharmony_ci unsigned char patchnumbuf[2]; 152062306a36Sopenharmony_ci int i; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "synth control with " 152362306a36Sopenharmony_ci "cmd 0x%x\n", wc->cmd); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci /* Pre-handling of or for various commands */ 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci switch (wc->cmd) { 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci case WFC_DISABLE_INTERRUPTS: 153062306a36Sopenharmony_ci snd_printk ("interrupts disabled.\n"); 153162306a36Sopenharmony_ci outb (0x80|0x20, dev->control_port); 153262306a36Sopenharmony_ci dev->interrupts_are_midi = 1; 153362306a36Sopenharmony_ci return 0; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci case WFC_ENABLE_INTERRUPTS: 153662306a36Sopenharmony_ci snd_printk ("interrupts enabled.\n"); 153762306a36Sopenharmony_ci outb (0x80|0x40|0x20, dev->control_port); 153862306a36Sopenharmony_ci dev->interrupts_are_midi = 1; 153962306a36Sopenharmony_ci return 0; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci case WFC_INTERRUPT_STATUS: 154262306a36Sopenharmony_ci wc->rbuf[0] = dev->interrupts_are_midi; 154362306a36Sopenharmony_ci return 0; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci case WFC_ROMSAMPLES_RDONLY: 154662306a36Sopenharmony_ci dev->rom_samples_rdonly = wc->wbuf[0]; 154762306a36Sopenharmony_ci wc->status = 0; 154862306a36Sopenharmony_ci return 0; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci case WFC_IDENTIFY_SLOT_TYPE: 155162306a36Sopenharmony_ci i = wc->wbuf[0] | (wc->wbuf[1] << 7); 155262306a36Sopenharmony_ci if (i <0 || i >= WF_MAX_SAMPLE) { 155362306a36Sopenharmony_ci snd_printk ("invalid slot ID %d\n", 155462306a36Sopenharmony_ci i); 155562306a36Sopenharmony_ci wc->status = EINVAL; 155662306a36Sopenharmony_ci return -EINVAL; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci wc->rbuf[0] = dev->sample_status[i]; 155962306a36Sopenharmony_ci wc->status = 0; 156062306a36Sopenharmony_ci return 0; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci case WFC_DEBUG_DRIVER: 156362306a36Sopenharmony_ci dev->debug = wc->wbuf[0]; 156462306a36Sopenharmony_ci snd_printk ("debug = 0x%x\n", dev->debug); 156562306a36Sopenharmony_ci return 0; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci case WFC_UPLOAD_PATCH: 156862306a36Sopenharmony_ci munge_int32 (*((u32 *) wc->wbuf), patchnumbuf, 2); 156962306a36Sopenharmony_ci memcpy (wc->wbuf, patchnumbuf, 2); 157062306a36Sopenharmony_ci break; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci case WFC_UPLOAD_MULTISAMPLE: 157362306a36Sopenharmony_ci /* multisamples have to be handled differently, and 157462306a36Sopenharmony_ci cannot be dealt with properly by snd_wavefront_cmd() alone. 157562306a36Sopenharmony_ci */ 157662306a36Sopenharmony_ci wc->status = wavefront_fetch_multisample 157762306a36Sopenharmony_ci (dev, (wavefront_patch_info *) wc->rbuf); 157862306a36Sopenharmony_ci return 0; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci case WFC_UPLOAD_SAMPLE_ALIAS: 158162306a36Sopenharmony_ci snd_printk ("support for sample alias upload " 158262306a36Sopenharmony_ci "being considered.\n"); 158362306a36Sopenharmony_ci wc->status = EINVAL; 158462306a36Sopenharmony_ci return -EINVAL; 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci wc->status = snd_wavefront_cmd (dev, wc->cmd, wc->rbuf, wc->wbuf); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci /* Post-handling of certain commands. 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci In particular, if the command was an upload, demunge the data 159262306a36Sopenharmony_ci so that the user-level doesn't have to think about it. 159362306a36Sopenharmony_ci */ 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (wc->status == 0) { 159662306a36Sopenharmony_ci switch (wc->cmd) { 159762306a36Sopenharmony_ci /* intercept any freemem requests so that we know 159862306a36Sopenharmony_ci we are always current with the user-level view 159962306a36Sopenharmony_ci of things. 160062306a36Sopenharmony_ci */ 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci case WFC_REPORT_FREE_MEMORY: 160362306a36Sopenharmony_ci dev->freemem = demunge_int32 (wc->rbuf, 4); 160462306a36Sopenharmony_ci break; 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci case WFC_UPLOAD_PATCH: 160762306a36Sopenharmony_ci demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); 160862306a36Sopenharmony_ci break; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci case WFC_UPLOAD_PROGRAM: 161162306a36Sopenharmony_ci demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); 161262306a36Sopenharmony_ci break; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci case WFC_UPLOAD_EDRUM_PROGRAM: 161562306a36Sopenharmony_ci demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); 161662306a36Sopenharmony_ci break; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci case WFC_UPLOAD_SAMPLE_HEADER: 161962306a36Sopenharmony_ci process_sample_hdr (wc->rbuf); 162062306a36Sopenharmony_ci break; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci case WFC_UPLOAD_SAMPLE_ALIAS: 162362306a36Sopenharmony_ci snd_printk ("support for " 162462306a36Sopenharmony_ci "sample aliases still " 162562306a36Sopenharmony_ci "being considered.\n"); 162662306a36Sopenharmony_ci break; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci case WFC_VMIDI_OFF: 162962306a36Sopenharmony_ci snd_wavefront_midi_disable_virtual (acard); 163062306a36Sopenharmony_ci break; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci case WFC_VMIDI_ON: 163362306a36Sopenharmony_ci snd_wavefront_midi_enable_virtual (acard); 163462306a36Sopenharmony_ci break; 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci return 0; 163962306a36Sopenharmony_ci} 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ciint 164262306a36Sopenharmony_cisnd_wavefront_synth_open (struct snd_hwdep *hw, struct file *file) 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci{ 164562306a36Sopenharmony_ci if (!try_module_get(hw->card->module)) 164662306a36Sopenharmony_ci return -EFAULT; 164762306a36Sopenharmony_ci file->private_data = hw; 164862306a36Sopenharmony_ci return 0; 164962306a36Sopenharmony_ci} 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ciint 165262306a36Sopenharmony_cisnd_wavefront_synth_release (struct snd_hwdep *hw, struct file *file) 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci{ 165562306a36Sopenharmony_ci module_put(hw->card->module); 165662306a36Sopenharmony_ci return 0; 165762306a36Sopenharmony_ci} 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ciint 166062306a36Sopenharmony_cisnd_wavefront_synth_ioctl (struct snd_hwdep *hw, struct file *file, 166162306a36Sopenharmony_ci unsigned int cmd, unsigned long arg) 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct snd_card *card; 166562306a36Sopenharmony_ci snd_wavefront_t *dev; 166662306a36Sopenharmony_ci snd_wavefront_card_t *acard; 166762306a36Sopenharmony_ci wavefront_control *wc; 166862306a36Sopenharmony_ci void __user *argp = (void __user *)arg; 166962306a36Sopenharmony_ci int err; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci card = (struct snd_card *) hw->card; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (snd_BUG_ON(!card)) 167462306a36Sopenharmony_ci return -ENODEV; 167562306a36Sopenharmony_ci if (snd_BUG_ON(!card->private_data)) 167662306a36Sopenharmony_ci return -ENODEV; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci acard = card->private_data; 167962306a36Sopenharmony_ci dev = &acard->wavefront; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci switch (cmd) { 168262306a36Sopenharmony_ci case WFCTL_LOAD_SPP: 168362306a36Sopenharmony_ci if (wavefront_load_patch (dev, argp) != 0) { 168462306a36Sopenharmony_ci return -EIO; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci break; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_ci case WFCTL_WFCMD: 168962306a36Sopenharmony_ci wc = memdup_user(argp, sizeof(*wc)); 169062306a36Sopenharmony_ci if (IS_ERR(wc)) 169162306a36Sopenharmony_ci return PTR_ERR(wc); 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci if (wavefront_synth_control (acard, wc) < 0) 169462306a36Sopenharmony_ci err = -EIO; 169562306a36Sopenharmony_ci else if (copy_to_user (argp, wc, sizeof (*wc))) 169662306a36Sopenharmony_ci err = -EFAULT; 169762306a36Sopenharmony_ci else 169862306a36Sopenharmony_ci err = 0; 169962306a36Sopenharmony_ci kfree(wc); 170062306a36Sopenharmony_ci return err; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci default: 170362306a36Sopenharmony_ci return -EINVAL; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci return 0; 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_ci/***********************************************************************/ 171162306a36Sopenharmony_ci/* WaveFront: interface for card-level wavefront module */ 171262306a36Sopenharmony_ci/***********************************************************************/ 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_civoid 171562306a36Sopenharmony_cisnd_wavefront_internal_interrupt (snd_wavefront_card_t *card) 171662306a36Sopenharmony_ci{ 171762306a36Sopenharmony_ci snd_wavefront_t *dev = &card->wavefront; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci /* 172062306a36Sopenharmony_ci Some comments on interrupts. I attempted a version of this 172162306a36Sopenharmony_ci driver that used interrupts throughout the code instead of 172262306a36Sopenharmony_ci doing busy and/or sleep-waiting. Alas, it appears that once 172362306a36Sopenharmony_ci the Motorola firmware is downloaded, the card *never* 172462306a36Sopenharmony_ci generates an RX interrupt. These are successfully generated 172562306a36Sopenharmony_ci during firmware loading, and after that wavefront_status() 172662306a36Sopenharmony_ci reports that an interrupt is pending on the card from time 172762306a36Sopenharmony_ci to time, but it never seems to be delivered to this 172862306a36Sopenharmony_ci driver. Note also that wavefront_status() continues to 172962306a36Sopenharmony_ci report that RX interrupts are enabled, suggesting that I 173062306a36Sopenharmony_ci didn't goof up and disable them by mistake. 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci Thus, I stepped back to a prior version of 173362306a36Sopenharmony_ci wavefront_wait(), the only place where this really 173462306a36Sopenharmony_ci matters. Its sad, but I've looked through the code to check 173562306a36Sopenharmony_ci on things, and I really feel certain that the Motorola 173662306a36Sopenharmony_ci firmware prevents RX-ready interrupts. 173762306a36Sopenharmony_ci */ 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci if ((wavefront_status(dev) & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { 174062306a36Sopenharmony_ci return; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci spin_lock(&dev->irq_lock); 174462306a36Sopenharmony_ci dev->irq_ok = 1; 174562306a36Sopenharmony_ci dev->irq_cnt++; 174662306a36Sopenharmony_ci spin_unlock(&dev->irq_lock); 174762306a36Sopenharmony_ci wake_up(&dev->interrupt_sleeper); 174862306a36Sopenharmony_ci} 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci/* STATUS REGISTER 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci0 Host Rx Interrupt Enable (1=Enabled) 175362306a36Sopenharmony_ci1 Host Rx Register Full (1=Full) 175462306a36Sopenharmony_ci2 Host Rx Interrupt Pending (1=Interrupt) 175562306a36Sopenharmony_ci3 Unused 175662306a36Sopenharmony_ci4 Host Tx Interrupt (1=Enabled) 175762306a36Sopenharmony_ci5 Host Tx Register empty (1=Empty) 175862306a36Sopenharmony_ci6 Host Tx Interrupt Pending (1=Interrupt) 175962306a36Sopenharmony_ci7 Unused 176062306a36Sopenharmony_ci*/ 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_cistatic int 176362306a36Sopenharmony_cisnd_wavefront_interrupt_bits (int irq) 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci{ 176662306a36Sopenharmony_ci int bits; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci switch (irq) { 176962306a36Sopenharmony_ci case 9: 177062306a36Sopenharmony_ci bits = 0x00; 177162306a36Sopenharmony_ci break; 177262306a36Sopenharmony_ci case 5: 177362306a36Sopenharmony_ci bits = 0x08; 177462306a36Sopenharmony_ci break; 177562306a36Sopenharmony_ci case 12: 177662306a36Sopenharmony_ci bits = 0x10; 177762306a36Sopenharmony_ci break; 177862306a36Sopenharmony_ci case 15: 177962306a36Sopenharmony_ci bits = 0x18; 178062306a36Sopenharmony_ci break; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci default: 178362306a36Sopenharmony_ci snd_printk ("invalid IRQ %d\n", irq); 178462306a36Sopenharmony_ci bits = -1; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci 178762306a36Sopenharmony_ci return bits; 178862306a36Sopenharmony_ci} 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_cistatic void 179162306a36Sopenharmony_ciwavefront_should_cause_interrupt (snd_wavefront_t *dev, 179262306a36Sopenharmony_ci int val, int port, unsigned long timeout) 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci{ 179562306a36Sopenharmony_ci wait_queue_entry_t wait; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci init_waitqueue_entry(&wait, current); 179862306a36Sopenharmony_ci spin_lock_irq(&dev->irq_lock); 179962306a36Sopenharmony_ci add_wait_queue(&dev->interrupt_sleeper, &wait); 180062306a36Sopenharmony_ci dev->irq_ok = 0; 180162306a36Sopenharmony_ci outb (val,port); 180262306a36Sopenharmony_ci spin_unlock_irq(&dev->irq_lock); 180362306a36Sopenharmony_ci while (!dev->irq_ok && time_before(jiffies, timeout)) { 180462306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 180562306a36Sopenharmony_ci barrier(); 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_cistatic int 181062306a36Sopenharmony_ciwavefront_reset_to_cleanliness (snd_wavefront_t *dev) 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci int bits; 181462306a36Sopenharmony_ci int hwv[2]; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci /* IRQ already checked */ 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci bits = snd_wavefront_interrupt_bits (dev->irq); 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* try reset of port */ 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci outb (0x0, dev->control_port); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci /* At this point, the board is in reset, and the H/W initialization 182562306a36Sopenharmony_ci register is accessed at the same address as the data port. 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci Bit 7 - Enable IRQ Driver 182862306a36Sopenharmony_ci 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs 182962306a36Sopenharmony_ci 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci Bit 6 - MIDI Interface Select 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci 0 - Use the MIDI Input from the 26-pin WaveBlaster 183462306a36Sopenharmony_ci compatible header as the serial MIDI source 183562306a36Sopenharmony_ci 1 - Use the MIDI Input from the 9-pin D connector as the 183662306a36Sopenharmony_ci serial MIDI source. 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci Bits 5:3 - IRQ Selection 183962306a36Sopenharmony_ci 0 0 0 - IRQ 2/9 184062306a36Sopenharmony_ci 0 0 1 - IRQ 5 184162306a36Sopenharmony_ci 0 1 0 - IRQ 12 184262306a36Sopenharmony_ci 0 1 1 - IRQ 15 184362306a36Sopenharmony_ci 1 0 0 - Reserved 184462306a36Sopenharmony_ci 1 0 1 - Reserved 184562306a36Sopenharmony_ci 1 1 0 - Reserved 184662306a36Sopenharmony_ci 1 1 1 - Reserved 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci Bits 2:1 - Reserved 184962306a36Sopenharmony_ci Bit 0 - Disable Boot ROM 185062306a36Sopenharmony_ci 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM 185162306a36Sopenharmony_ci 1 - memory accesses to 03FC30-03FFFFH are directed to external 185262306a36Sopenharmony_ci storage. 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci */ 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci /* configure hardware: IRQ, enable interrupts, 185762306a36Sopenharmony_ci plus external 9-pin MIDI interface selected 185862306a36Sopenharmony_ci */ 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci outb (0x80 | 0x40 | bits, dev->data_port); 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci /* CONTROL REGISTER 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci 0 Host Rx Interrupt Enable (1=Enabled) 0x1 186562306a36Sopenharmony_ci 1 Unused 0x2 186662306a36Sopenharmony_ci 2 Unused 0x4 186762306a36Sopenharmony_ci 3 Unused 0x8 186862306a36Sopenharmony_ci 4 Host Tx Interrupt Enable 0x10 186962306a36Sopenharmony_ci 5 Mute (0=Mute; 1=Play) 0x20 187062306a36Sopenharmony_ci 6 Master Interrupt Enable (1=Enabled) 0x40 187162306a36Sopenharmony_ci 7 Master Reset (0=Reset; 1=Run) 0x80 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci Take us out of reset, mute output, master + TX + RX interrupts on. 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci We'll get an interrupt presumably to tell us that the TX 187662306a36Sopenharmony_ci register is clear. 187762306a36Sopenharmony_ci */ 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci wavefront_should_cause_interrupt(dev, 0x80|0x40|0x10|0x1, 188062306a36Sopenharmony_ci dev->control_port, 188162306a36Sopenharmony_ci (reset_time*HZ)/100); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci /* Note: data port is now the data port, not the h/w initialization 188462306a36Sopenharmony_ci port. 188562306a36Sopenharmony_ci */ 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci if (!dev->irq_ok) { 188862306a36Sopenharmony_ci snd_printk ("intr not received after h/w un-reset.\n"); 188962306a36Sopenharmony_ci goto gone_bad; 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci /* Note: data port is now the data port, not the h/w initialization 189362306a36Sopenharmony_ci port. 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci At this point, only "HW VERSION" or "DOWNLOAD OS" commands 189662306a36Sopenharmony_ci will work. So, issue one of them, and wait for TX 189762306a36Sopenharmony_ci interrupt. This can take a *long* time after a cold boot, 189862306a36Sopenharmony_ci while the ISC ROM does its RAM test. The SDK says up to 4 189962306a36Sopenharmony_ci seconds - with 12MB of RAM on a Tropez+, it takes a lot 190062306a36Sopenharmony_ci longer than that (~16secs). Note that the card understands 190162306a36Sopenharmony_ci the difference between a warm and a cold boot, so 190262306a36Sopenharmony_ci subsequent ISC2115 reboots (say, caused by module 190362306a36Sopenharmony_ci reloading) will get through this much faster. 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci XXX Interesting question: why is no RX interrupt received first ? 190662306a36Sopenharmony_ci */ 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci wavefront_should_cause_interrupt(dev, WFC_HARDWARE_VERSION, 190962306a36Sopenharmony_ci dev->data_port, ramcheck_time*HZ); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci if (!dev->irq_ok) { 191262306a36Sopenharmony_ci snd_printk ("post-RAM-check interrupt not received.\n"); 191362306a36Sopenharmony_ci goto gone_bad; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci if (!wavefront_wait (dev, STAT_CAN_READ)) { 191762306a36Sopenharmony_ci snd_printk ("no response to HW version cmd.\n"); 191862306a36Sopenharmony_ci goto gone_bad; 191962306a36Sopenharmony_ci } 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci hwv[0] = wavefront_read(dev); 192262306a36Sopenharmony_ci if (hwv[0] == -1) { 192362306a36Sopenharmony_ci snd_printk ("board not responding correctly.\n"); 192462306a36Sopenharmony_ci goto gone_bad; 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (hwv[0] == 0xFF) { /* NAK */ 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci /* Board's RAM test failed. Try to read error code, 193062306a36Sopenharmony_ci and tell us about it either way. 193162306a36Sopenharmony_ci */ 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci hwv[0] = wavefront_read(dev); 193462306a36Sopenharmony_ci if (hwv[0] == -1) { 193562306a36Sopenharmony_ci snd_printk ("on-board RAM test failed " 193662306a36Sopenharmony_ci "(bad error code).\n"); 193762306a36Sopenharmony_ci } else { 193862306a36Sopenharmony_ci snd_printk ("on-board RAM test failed " 193962306a36Sopenharmony_ci "(error code: 0x%x).\n", 194062306a36Sopenharmony_ci hwv[0]); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci goto gone_bad; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* We're OK, just get the next byte of the HW version response */ 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci hwv[1] = wavefront_read(dev); 194862306a36Sopenharmony_ci if (hwv[1] == -1) { 194962306a36Sopenharmony_ci snd_printk ("incorrect h/w response.\n"); 195062306a36Sopenharmony_ci goto gone_bad; 195162306a36Sopenharmony_ci } 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci snd_printk ("hardware version %d.%d\n", 195462306a36Sopenharmony_ci hwv[0], hwv[1]); 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci return 0; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci gone_bad: 196062306a36Sopenharmony_ci return (1); 196162306a36Sopenharmony_ci} 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_cistatic int 196462306a36Sopenharmony_ciwavefront_download_firmware (snd_wavefront_t *dev, char *path) 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci{ 196762306a36Sopenharmony_ci const unsigned char *buf; 196862306a36Sopenharmony_ci int len, err; 196962306a36Sopenharmony_ci int section_cnt_downloaded = 0; 197062306a36Sopenharmony_ci const struct firmware *firmware; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci err = request_firmware(&firmware, path, dev->card->dev); 197362306a36Sopenharmony_ci if (err < 0) { 197462306a36Sopenharmony_ci snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path); 197562306a36Sopenharmony_ci return 1; 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci len = 0; 197962306a36Sopenharmony_ci buf = firmware->data; 198062306a36Sopenharmony_ci for (;;) { 198162306a36Sopenharmony_ci int section_length = *(signed char *)buf; 198262306a36Sopenharmony_ci if (section_length == 0) 198362306a36Sopenharmony_ci break; 198462306a36Sopenharmony_ci if (section_length < 0 || section_length > WF_SECTION_MAX) { 198562306a36Sopenharmony_ci snd_printk(KERN_ERR 198662306a36Sopenharmony_ci "invalid firmware section length %d\n", 198762306a36Sopenharmony_ci section_length); 198862306a36Sopenharmony_ci goto failure; 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci buf++; 199162306a36Sopenharmony_ci len++; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci if (firmware->size < len + section_length) { 199462306a36Sopenharmony_ci snd_printk(KERN_ERR "firmware section read error.\n"); 199562306a36Sopenharmony_ci goto failure; 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* Send command */ 199962306a36Sopenharmony_ci if (wavefront_write(dev, WFC_DOWNLOAD_OS)) 200062306a36Sopenharmony_ci goto failure; 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci for (; section_length; section_length--) { 200362306a36Sopenharmony_ci if (wavefront_write(dev, *buf)) 200462306a36Sopenharmony_ci goto failure; 200562306a36Sopenharmony_ci buf++; 200662306a36Sopenharmony_ci len++; 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci /* get ACK */ 201062306a36Sopenharmony_ci if (!wavefront_wait(dev, STAT_CAN_READ)) { 201162306a36Sopenharmony_ci snd_printk(KERN_ERR "time out for firmware ACK.\n"); 201262306a36Sopenharmony_ci goto failure; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci err = inb(dev->data_port); 201562306a36Sopenharmony_ci if (err != WF_ACK) { 201662306a36Sopenharmony_ci snd_printk(KERN_ERR 201762306a36Sopenharmony_ci "download of section #%d not " 201862306a36Sopenharmony_ci "acknowledged, ack = 0x%x\n", 201962306a36Sopenharmony_ci section_cnt_downloaded + 1, err); 202062306a36Sopenharmony_ci goto failure; 202162306a36Sopenharmony_ci } 202262306a36Sopenharmony_ci 202362306a36Sopenharmony_ci section_cnt_downloaded++; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci release_firmware(firmware); 202762306a36Sopenharmony_ci return 0; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci failure: 203062306a36Sopenharmony_ci release_firmware(firmware); 203162306a36Sopenharmony_ci snd_printk(KERN_ERR "firmware download failed!!!\n"); 203262306a36Sopenharmony_ci return 1; 203362306a36Sopenharmony_ci} 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_cistatic int 203762306a36Sopenharmony_ciwavefront_do_reset (snd_wavefront_t *dev) 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci char voices[1]; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci if (wavefront_reset_to_cleanliness (dev)) { 204362306a36Sopenharmony_ci snd_printk ("hw reset failed.\n"); 204462306a36Sopenharmony_ci goto gone_bad; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci if (dev->israw) { 204862306a36Sopenharmony_ci if (wavefront_download_firmware (dev, ospath)) { 204962306a36Sopenharmony_ci goto gone_bad; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci dev->israw = 0; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci /* Wait for the OS to get running. The protocol for 205562306a36Sopenharmony_ci this is non-obvious, and was determined by 205662306a36Sopenharmony_ci using port-IO tracing in DOSemu and some 205762306a36Sopenharmony_ci experimentation here. 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci Rather than using timed waits, use interrupts creatively. 206062306a36Sopenharmony_ci */ 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci wavefront_should_cause_interrupt (dev, WFC_NOOP, 206362306a36Sopenharmony_ci dev->data_port, 206462306a36Sopenharmony_ci (osrun_time*HZ)); 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci if (!dev->irq_ok) { 206762306a36Sopenharmony_ci snd_printk ("no post-OS interrupt.\n"); 206862306a36Sopenharmony_ci goto gone_bad; 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci /* Now, do it again ! */ 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci wavefront_should_cause_interrupt (dev, WFC_NOOP, 207462306a36Sopenharmony_ci dev->data_port, (10*HZ)); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci if (!dev->irq_ok) { 207762306a36Sopenharmony_ci snd_printk ("no post-OS interrupt(2).\n"); 207862306a36Sopenharmony_ci goto gone_bad; 207962306a36Sopenharmony_ci } 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci /* OK, no (RX/TX) interrupts any more, but leave mute 208262306a36Sopenharmony_ci in effect. 208362306a36Sopenharmony_ci */ 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci outb (0x80|0x40, dev->control_port); 208662306a36Sopenharmony_ci } 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci /* SETUPSND.EXE asks for sample memory config here, but since i 208962306a36Sopenharmony_ci have no idea how to interpret the result, we'll forget 209062306a36Sopenharmony_ci about it. 209162306a36Sopenharmony_ci */ 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci dev->freemem = wavefront_freemem(dev); 209462306a36Sopenharmony_ci if (dev->freemem < 0) 209562306a36Sopenharmony_ci goto gone_bad; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci snd_printk ("available DRAM %dk\n", dev->freemem / 1024); 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci if (wavefront_write (dev, 0xf0) || 210062306a36Sopenharmony_ci wavefront_write (dev, 1) || 210162306a36Sopenharmony_ci (wavefront_read (dev) < 0)) { 210262306a36Sopenharmony_ci dev->debug = 0; 210362306a36Sopenharmony_ci snd_printk ("MPU emulation mode not set.\n"); 210462306a36Sopenharmony_ci goto gone_bad; 210562306a36Sopenharmony_ci } 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci voices[0] = 32; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_SET_NVOICES, NULL, voices)) { 211062306a36Sopenharmony_ci snd_printk ("cannot set number of voices to 32.\n"); 211162306a36Sopenharmony_ci goto gone_bad; 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci return 0; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci gone_bad: 211862306a36Sopenharmony_ci /* reset that sucker so that it doesn't bother us. */ 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci outb (0x0, dev->control_port); 212162306a36Sopenharmony_ci dev->interrupts_are_midi = 0; 212262306a36Sopenharmony_ci return 1; 212362306a36Sopenharmony_ci} 212462306a36Sopenharmony_ci 212562306a36Sopenharmony_ciint 212662306a36Sopenharmony_cisnd_wavefront_start (snd_wavefront_t *dev) 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci{ 212962306a36Sopenharmony_ci int samples_are_from_rom; 213062306a36Sopenharmony_ci 213162306a36Sopenharmony_ci /* IMPORTANT: assumes that snd_wavefront_detect() and/or 213262306a36Sopenharmony_ci wavefront_reset_to_cleanliness() has already been called 213362306a36Sopenharmony_ci */ 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci if (dev->israw) { 213662306a36Sopenharmony_ci samples_are_from_rom = 1; 213762306a36Sopenharmony_ci } else { 213862306a36Sopenharmony_ci /* XXX is this always true ? */ 213962306a36Sopenharmony_ci samples_are_from_rom = 0; 214062306a36Sopenharmony_ci } 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (dev->israw || fx_raw) { 214362306a36Sopenharmony_ci if (wavefront_do_reset (dev)) { 214462306a36Sopenharmony_ci return -1; 214562306a36Sopenharmony_ci } 214662306a36Sopenharmony_ci } 214762306a36Sopenharmony_ci /* Check for FX device, present only on Tropez+ */ 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci dev->has_fx = (snd_wavefront_fx_detect (dev) == 0); 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci if (dev->has_fx && fx_raw) { 215262306a36Sopenharmony_ci snd_wavefront_fx_start (dev); 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci wavefront_get_sample_status (dev, samples_are_from_rom); 215662306a36Sopenharmony_ci wavefront_get_program_status (dev); 215762306a36Sopenharmony_ci wavefront_get_patch_status (dev); 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci /* Start normal operation: unreset, master interrupt enabled, no mute 216062306a36Sopenharmony_ci */ 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci outb (0x80|0x40|0x20, dev->control_port); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci return (0); 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ciint 216862306a36Sopenharmony_cisnd_wavefront_detect (snd_wavefront_card_t *card) 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci{ 217162306a36Sopenharmony_ci unsigned char rbuf[4], wbuf[4]; 217262306a36Sopenharmony_ci snd_wavefront_t *dev = &card->wavefront; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci /* returns zero if a WaveFront card is successfully detected. 217562306a36Sopenharmony_ci negative otherwise. 217662306a36Sopenharmony_ci */ 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci dev->israw = 0; 217962306a36Sopenharmony_ci dev->has_fx = 0; 218062306a36Sopenharmony_ci dev->debug = debug_default; 218162306a36Sopenharmony_ci dev->interrupts_are_midi = 0; 218262306a36Sopenharmony_ci dev->irq_cnt = 0; 218362306a36Sopenharmony_ci dev->rom_samples_rdonly = 1; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci dev->fw_version[0] = rbuf[0]; 218862306a36Sopenharmony_ci dev->fw_version[1] = rbuf[1]; 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci snd_printk ("firmware %d.%d already loaded.\n", 219162306a36Sopenharmony_ci rbuf[0], rbuf[1]); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci /* check that a command actually works */ 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_HARDWARE_VERSION, 219662306a36Sopenharmony_ci rbuf, wbuf) == 0) { 219762306a36Sopenharmony_ci dev->hw_version[0] = rbuf[0]; 219862306a36Sopenharmony_ci dev->hw_version[1] = rbuf[1]; 219962306a36Sopenharmony_ci } else { 220062306a36Sopenharmony_ci snd_printk ("not raw, but no " 220162306a36Sopenharmony_ci "hardware version!\n"); 220262306a36Sopenharmony_ci return -1; 220362306a36Sopenharmony_ci } 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci if (!wf_raw) { 220662306a36Sopenharmony_ci return 0; 220762306a36Sopenharmony_ci } else { 220862306a36Sopenharmony_ci snd_printk ("reloading firmware as you requested.\n"); 220962306a36Sopenharmony_ci dev->israw = 1; 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci } else { 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci dev->israw = 1; 221562306a36Sopenharmony_ci snd_printk ("no response to firmware probe, assume raw.\n"); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci return 0; 222062306a36Sopenharmony_ci} 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ciMODULE_FIRMWARE(DEFAULT_OSPATH); 2223