18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Copyright (C) by Paul Barton-Davis 1998-1999 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Some portions of this file are taken from work that is 58c2ecf20Sopenharmony_ci * copyright (C) by Hannu Savolainen 1993-1996 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * An ALSA lowlevel driver for Turtle Beach ICS2115 wavetable synth 108c2ecf20Sopenharmony_ci * (Maui, Tropez, Tropez Plus) 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This driver supports the onboard wavetable synthesizer (an ICS2115), 138c2ecf20Sopenharmony_ci * including patch, sample and program loading and unloading, conversion 148c2ecf20Sopenharmony_ci * of GUS patches during loading, and full user-level access to all 158c2ecf20Sopenharmony_ci * WaveFront commands. It tries to provide semi-intelligent patch and 168c2ecf20Sopenharmony_ci * sample management as well. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/init.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/time.h> 258c2ecf20Sopenharmony_ci#include <linux/wait.h> 268c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 278c2ecf20Sopenharmony_ci#include <linux/firmware.h> 288c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <sound/core.h> 328c2ecf20Sopenharmony_ci#include <sound/snd_wavefront.h> 338c2ecf20Sopenharmony_ci#include <sound/initval.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int wf_raw = 0; /* we normally check for "raw state" to firmware 368c2ecf20Sopenharmony_ci loading. if non-zero, then during driver loading, the 378c2ecf20Sopenharmony_ci state of the board is ignored, and we reset the 388c2ecf20Sopenharmony_ci board and load the firmware anyway. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int fx_raw = 1; /* if this is zero, we'll leave the FX processor in 428c2ecf20Sopenharmony_ci whatever state it is when the driver is loaded. 438c2ecf20Sopenharmony_ci The default is to download the microprogram and 448c2ecf20Sopenharmony_ci associated coefficients to set it up for "default" 458c2ecf20Sopenharmony_ci operation, whatever that means. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int debug_default = 0; /* you can set this to control debugging 498c2ecf20Sopenharmony_ci during driver loading. it takes any combination 508c2ecf20Sopenharmony_ci of the WF_DEBUG_* flags defined in 518c2ecf20Sopenharmony_ci wavefront.h 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* XXX this needs to be made firmware and hardware version dependent */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define DEFAULT_OSPATH "wavefront.os" 578c2ecf20Sopenharmony_cistatic char *ospath = DEFAULT_OSPATH; /* the firmware file name */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int wait_usecs = 150; /* This magic number seems to give pretty optimal 608c2ecf20Sopenharmony_ci throughput based on my limited experimentation. 618c2ecf20Sopenharmony_ci If you want to play around with it and find a better 628c2ecf20Sopenharmony_ci value, be my guest. Remember, the idea is to 638c2ecf20Sopenharmony_ci get a number that causes us to just busy wait 648c2ecf20Sopenharmony_ci for as many WaveFront commands as possible, without 658c2ecf20Sopenharmony_ci coming up with a number so large that we hog the 668c2ecf20Sopenharmony_ci whole CPU. 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci Specifically, with this number, out of about 134,000 698c2ecf20Sopenharmony_ci status waits, only about 250 result in a sleep. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int sleep_interval = 100; /* HZ/sleep_interval seconds per sleep */ 738c2ecf20Sopenharmony_cistatic int sleep_tries = 50; /* number of times we'll try to sleep */ 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int reset_time = 2; /* hundreths of a second we wait after a HW 768c2ecf20Sopenharmony_ci reset for the expected interrupt. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int ramcheck_time = 20; /* time in seconds to wait while ROM code 808c2ecf20Sopenharmony_ci checks on-board RAM. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int osrun_time = 10; /* time in seconds we wait for the OS to 848c2ecf20Sopenharmony_ci start running. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cimodule_param(wf_raw, int, 0444); 878c2ecf20Sopenharmony_ciMODULE_PARM_DESC(wf_raw, "if non-zero, assume that we need to boot the OS"); 888c2ecf20Sopenharmony_cimodule_param(fx_raw, int, 0444); 898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fx_raw, "if non-zero, assume that the FX process needs help"); 908c2ecf20Sopenharmony_cimodule_param(debug_default, int, 0444); 918c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_default, "debug parameters for card initialization"); 928c2ecf20Sopenharmony_cimodule_param(wait_usecs, int, 0444); 938c2ecf20Sopenharmony_ciMODULE_PARM_DESC(wait_usecs, "how long to wait without sleeping, usecs"); 948c2ecf20Sopenharmony_cimodule_param(sleep_interval, int, 0444); 958c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply"); 968c2ecf20Sopenharmony_cimodule_param(sleep_tries, int, 0444); 978c2ecf20Sopenharmony_ciMODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait"); 988c2ecf20Sopenharmony_cimodule_param(ospath, charp, 0444); 998c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ospath, "pathname to processed ICS2115 OS firmware"); 1008c2ecf20Sopenharmony_cimodule_param(reset_time, int, 0444); 1018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect"); 1028c2ecf20Sopenharmony_cimodule_param(ramcheck_time, int, 0444); 1038c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test"); 1048c2ecf20Sopenharmony_cimodule_param(osrun_time, int, 0444); 1058c2ecf20Sopenharmony_ciMODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS"); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* if WF_DEBUG not defined, no run-time debugging messages will 1088c2ecf20Sopenharmony_ci be available via the debug flag setting. Given the current 1098c2ecf20Sopenharmony_ci beta state of the driver, this will remain set until a future 1108c2ecf20Sopenharmony_ci version. 1118c2ecf20Sopenharmony_ci*/ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define WF_DEBUG 1 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci#ifdef WF_DEBUG 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define DPRINT(cond, ...) \ 1188c2ecf20Sopenharmony_ci if ((dev->debug & (cond)) == (cond)) { \ 1198c2ecf20Sopenharmony_ci snd_printk (__VA_ARGS__); \ 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci#else 1228c2ecf20Sopenharmony_ci#define DPRINT(cond, args...) 1238c2ecf20Sopenharmony_ci#endif /* WF_DEBUG */ 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#define LOGNAME "WaveFront: " 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* bitmasks for WaveFront status port value */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#define STAT_RINTR_ENABLED 0x01 1308c2ecf20Sopenharmony_ci#define STAT_CAN_READ 0x02 1318c2ecf20Sopenharmony_ci#define STAT_INTR_READ 0x04 1328c2ecf20Sopenharmony_ci#define STAT_WINTR_ENABLED 0x10 1338c2ecf20Sopenharmony_ci#define STAT_CAN_WRITE 0x20 1348c2ecf20Sopenharmony_ci#define STAT_INTR_WRITE 0x40 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int wavefront_delete_sample (snd_wavefront_t *, int sampnum); 1378c2ecf20Sopenharmony_cistatic int wavefront_find_free_sample (snd_wavefront_t *); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistruct wavefront_command { 1408c2ecf20Sopenharmony_ci int cmd; 1418c2ecf20Sopenharmony_ci char *action; 1428c2ecf20Sopenharmony_ci unsigned int read_cnt; 1438c2ecf20Sopenharmony_ci unsigned int write_cnt; 1448c2ecf20Sopenharmony_ci int need_ack; 1458c2ecf20Sopenharmony_ci}; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic struct { 1488c2ecf20Sopenharmony_ci int errno; 1498c2ecf20Sopenharmony_ci const char *errstr; 1508c2ecf20Sopenharmony_ci} wavefront_errors[] = { 1518c2ecf20Sopenharmony_ci { 0x01, "Bad sample number" }, 1528c2ecf20Sopenharmony_ci { 0x02, "Out of sample memory" }, 1538c2ecf20Sopenharmony_ci { 0x03, "Bad patch number" }, 1548c2ecf20Sopenharmony_ci { 0x04, "Error in number of voices" }, 1558c2ecf20Sopenharmony_ci { 0x06, "Sample load already in progress" }, 1568c2ecf20Sopenharmony_ci { 0x0B, "No sample load request pending" }, 1578c2ecf20Sopenharmony_ci { 0x0E, "Bad MIDI channel number" }, 1588c2ecf20Sopenharmony_ci { 0x10, "Download Record Error" }, 1598c2ecf20Sopenharmony_ci { 0x80, "Success" }, 1608c2ecf20Sopenharmony_ci { 0x0 } 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci#define NEEDS_ACK 1 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic struct wavefront_command wavefront_commands[] = { 1668c2ecf20Sopenharmony_ci { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK }, 1678c2ecf20Sopenharmony_ci { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0}, 1688c2ecf20Sopenharmony_ci { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK }, 1698c2ecf20Sopenharmony_ci { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 }, 1708c2ecf20Sopenharmony_ci { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK }, 1718c2ecf20Sopenharmony_ci { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 }, 1728c2ecf20Sopenharmony_ci { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK }, 1738c2ecf20Sopenharmony_ci { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK }, 1748c2ecf20Sopenharmony_ci { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 }, 1758c2ecf20Sopenharmony_ci { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK }, 1768c2ecf20Sopenharmony_ci { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK }, 1778c2ecf20Sopenharmony_ci { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK }, 1788c2ecf20Sopenharmony_ci { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK }, 1798c2ecf20Sopenharmony_ci { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 }, 1808c2ecf20Sopenharmony_ci { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 }, 1818c2ecf20Sopenharmony_ci { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 }, 1828c2ecf20Sopenharmony_ci { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 }, 1838c2ecf20Sopenharmony_ci { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 }, 1848c2ecf20Sopenharmony_ci { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 }, 1858c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_SAMPLE, "download sample", 1868c2ecf20Sopenharmony_ci 0, WF_SAMPLE_BYTES, NEEDS_ACK }, 1878c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK}, 1888c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header", 1898c2ecf20Sopenharmony_ci 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK }, 1908c2ecf20Sopenharmony_ci { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 }, 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* This command requires a variable number of bytes to be written. 1938c2ecf20Sopenharmony_ci There is a hack in snd_wavefront_cmd() to support this. The actual 1948c2ecf20Sopenharmony_ci count is passed in as the read buffer ptr, cast appropriately. 1958c2ecf20Sopenharmony_ci Ugh. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK }, 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* This one is a hack as well. We just read the first byte of the 2018c2ecf20Sopenharmony_ci response, don't fetch an ACK, and leave the rest to the 2028c2ecf20Sopenharmony_ci calling function. Ugly, ugly, ugly. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 }, 2068c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias", 2078c2ecf20Sopenharmony_ci 0, WF_ALIAS_BYTES, NEEDS_ACK }, 2088c2ecf20Sopenharmony_ci { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0}, 2098c2ecf20Sopenharmony_ci { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK }, 2108c2ecf20Sopenharmony_ci { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 }, 2118c2ecf20Sopenharmony_ci { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" }, 2128c2ecf20Sopenharmony_ci { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 }, 2138c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK }, 2148c2ecf20Sopenharmony_ci { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 }, 2158c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK }, 2168c2ecf20Sopenharmony_ci { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 }, 2178c2ecf20Sopenharmony_ci { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9, 2188c2ecf20Sopenharmony_ci NEEDS_ACK}, 2198c2ecf20Sopenharmony_ci { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0}, 2208c2ecf20Sopenharmony_ci { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel", 2218c2ecf20Sopenharmony_ci 0, 1, NEEDS_ACK }, 2228c2ecf20Sopenharmony_ci { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, 2238c2ecf20Sopenharmony_ci { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", 2248c2ecf20Sopenharmony_ci 32, 0, 0 }, 2258c2ecf20Sopenharmony_ci { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, 2268c2ecf20Sopenharmony_ci { 0x00 } 2278c2ecf20Sopenharmony_ci}; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic const char * 2308c2ecf20Sopenharmony_ciwavefront_errorstr (int errnum) 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci int i; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci for (i = 0; wavefront_errors[i].errstr; i++) { 2368c2ecf20Sopenharmony_ci if (wavefront_errors[i].errno == errnum) { 2378c2ecf20Sopenharmony_ci return wavefront_errors[i].errstr; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return "Unknown WaveFront error"; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic struct wavefront_command * 2458c2ecf20Sopenharmony_ciwavefront_get_command (int cmd) 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int i; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci for (i = 0; wavefront_commands[i].cmd != 0; i++) { 2518c2ecf20Sopenharmony_ci if (cmd == wavefront_commands[i].cmd) { 2528c2ecf20Sopenharmony_ci return &wavefront_commands[i]; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return NULL; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic inline int 2608c2ecf20Sopenharmony_ciwavefront_status (snd_wavefront_t *dev) 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci return inb (dev->status_port); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic int 2678c2ecf20Sopenharmony_ciwavefront_sleep (int limit) 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci schedule_timeout_interruptible(limit); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return signal_pending(current); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int 2768c2ecf20Sopenharmony_ciwavefront_wait (snd_wavefront_t *dev, int mask) 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci int i; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Spin for a short period of time, because >99% of all 2828c2ecf20Sopenharmony_ci requests to the WaveFront can be serviced inline like this. 2838c2ecf20Sopenharmony_ci */ 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci for (i = 0; i < wait_usecs; i += 5) { 2868c2ecf20Sopenharmony_ci if (wavefront_status (dev) & mask) { 2878c2ecf20Sopenharmony_ci return 1; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci udelay(5); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci for (i = 0; i < sleep_tries; i++) { 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (wavefront_status (dev) & mask) { 2958c2ecf20Sopenharmony_ci return 1; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (wavefront_sleep (HZ/sleep_interval)) { 2998c2ecf20Sopenharmony_ci return (0); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return (0); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int 3078c2ecf20Sopenharmony_ciwavefront_read (snd_wavefront_t *dev) 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci if (wavefront_wait (dev, STAT_CAN_READ)) 3118c2ecf20Sopenharmony_ci return inb (dev->data_port); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "read timeout.\n"); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return -1; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int 3198c2ecf20Sopenharmony_ciwavefront_write (snd_wavefront_t *dev, unsigned char data) 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci if (wavefront_wait (dev, STAT_CAN_WRITE)) { 3238c2ecf20Sopenharmony_ci outb (data, dev->data_port); 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "write timeout.\n"); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return -1; 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ciint 3338c2ecf20Sopenharmony_cisnd_wavefront_cmd (snd_wavefront_t *dev, 3348c2ecf20Sopenharmony_ci int cmd, unsigned char *rbuf, unsigned char *wbuf) 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci int ack; 3388c2ecf20Sopenharmony_ci unsigned int i; 3398c2ecf20Sopenharmony_ci int c; 3408c2ecf20Sopenharmony_ci struct wavefront_command *wfcmd; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if ((wfcmd = wavefront_get_command (cmd)) == NULL) { 3438c2ecf20Sopenharmony_ci snd_printk ("command 0x%x not supported.\n", 3448c2ecf20Sopenharmony_ci cmd); 3458c2ecf20Sopenharmony_ci return 1; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Hack to handle the one variable-size write command. See 3498c2ecf20Sopenharmony_ci wavefront_send_multisample() for the other half of this 3508c2ecf20Sopenharmony_ci gross and ugly strategy. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (cmd == WFC_DOWNLOAD_MULTISAMPLE) { 3548c2ecf20Sopenharmony_ci wfcmd->write_cnt = (unsigned long) rbuf; 3558c2ecf20Sopenharmony_ci rbuf = NULL; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n", 3598c2ecf20Sopenharmony_ci cmd, wfcmd->action, wfcmd->read_cnt, 3608c2ecf20Sopenharmony_ci wfcmd->write_cnt, wfcmd->need_ack); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (wavefront_write (dev, cmd)) { 3638c2ecf20Sopenharmony_ci DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request " 3648c2ecf20Sopenharmony_ci "0x%x [%s].\n", 3658c2ecf20Sopenharmony_ci cmd, wfcmd->action); 3668c2ecf20Sopenharmony_ci return 1; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (wfcmd->write_cnt > 0) { 3708c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "writing %d bytes " 3718c2ecf20Sopenharmony_ci "for 0x%x\n", 3728c2ecf20Sopenharmony_ci wfcmd->write_cnt, cmd); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (i = 0; i < wfcmd->write_cnt; i++) { 3758c2ecf20Sopenharmony_ci if (wavefront_write (dev, wbuf[i])) { 3768c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_IO, "bad write for byte " 3778c2ecf20Sopenharmony_ci "%d of 0x%x [%s].\n", 3788c2ecf20Sopenharmony_ci i, cmd, wfcmd->action); 3798c2ecf20Sopenharmony_ci return 1; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n", 3838c2ecf20Sopenharmony_ci i, wbuf[i]); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (wfcmd->read_cnt > 0) { 3888c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "reading %d ints " 3898c2ecf20Sopenharmony_ci "for 0x%x\n", 3908c2ecf20Sopenharmony_ci wfcmd->read_cnt, cmd); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci for (i = 0; i < wfcmd->read_cnt; i++) { 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if ((c = wavefront_read (dev)) == -1) { 3958c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_IO, "bad read for byte " 3968c2ecf20Sopenharmony_ci "%d of 0x%x [%s].\n", 3978c2ecf20Sopenharmony_ci i, cmd, wfcmd->action); 3988c2ecf20Sopenharmony_ci return 1; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Now handle errors. Lots of special cases here */ 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (c == 0xff) { 4048c2ecf20Sopenharmony_ci if ((c = wavefront_read (dev)) == -1) { 4058c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_IO, "bad read for " 4068c2ecf20Sopenharmony_ci "error byte at " 4078c2ecf20Sopenharmony_ci "read byte %d " 4088c2ecf20Sopenharmony_ci "of 0x%x [%s].\n", 4098c2ecf20Sopenharmony_ci i, cmd, 4108c2ecf20Sopenharmony_ci wfcmd->action); 4118c2ecf20Sopenharmony_ci return 1; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* Can you believe this madness ? */ 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (c == 1 && 4178c2ecf20Sopenharmony_ci wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { 4188c2ecf20Sopenharmony_ci rbuf[0] = WF_ST_EMPTY; 4198c2ecf20Sopenharmony_ci return (0); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci } else if (c == 3 && 4228c2ecf20Sopenharmony_ci wfcmd->cmd == WFC_UPLOAD_PATCH) { 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 3; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci } else if (c == 1 && 4278c2ecf20Sopenharmony_ci wfcmd->cmd == WFC_UPLOAD_PROGRAM) { 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 1; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci } else { 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_IO, "error %d (%s) " 4348c2ecf20Sopenharmony_ci "during " 4358c2ecf20Sopenharmony_ci "read for byte " 4368c2ecf20Sopenharmony_ci "%d of 0x%x " 4378c2ecf20Sopenharmony_ci "[%s].\n", 4388c2ecf20Sopenharmony_ci c, 4398c2ecf20Sopenharmony_ci wavefront_errorstr (c), 4408c2ecf20Sopenharmony_ci i, cmd, 4418c2ecf20Sopenharmony_ci wfcmd->action); 4428c2ecf20Sopenharmony_ci return 1; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci rbuf[i] = c; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Some commands need an ACK, but return zero instead 4598c2ecf20Sopenharmony_ci of the standard value. 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if ((ack = wavefront_read (dev)) == 0) { 4638c2ecf20Sopenharmony_ci ack = WF_ACK; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (ack != WF_ACK) { 4678c2ecf20Sopenharmony_ci if (ack == -1) { 4688c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_IO, "cannot read ack for " 4698c2ecf20Sopenharmony_ci "0x%x [%s].\n", 4708c2ecf20Sopenharmony_ci cmd, wfcmd->action); 4718c2ecf20Sopenharmony_ci return 1; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci } else { 4748c2ecf20Sopenharmony_ci int err = -1; /* something unknown */ 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (ack == 0xff) { /* explicit error */ 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if ((err = wavefront_read (dev)) == -1) { 4798c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, 4808c2ecf20Sopenharmony_ci "cannot read err " 4818c2ecf20Sopenharmony_ci "for 0x%x [%s].\n", 4828c2ecf20Sopenharmony_ci cmd, wfcmd->action); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_IO, "0x%x [%s] " 4878c2ecf20Sopenharmony_ci "failed (0x%x, 0x%x, %s)\n", 4888c2ecf20Sopenharmony_ci cmd, wfcmd->action, ack, err, 4898c2ecf20Sopenharmony_ci wavefront_errorstr (err)); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return -err; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "ack received " 4968c2ecf20Sopenharmony_ci "for 0x%x [%s]\n", 4978c2ecf20Sopenharmony_ci cmd, wfcmd->action); 4988c2ecf20Sopenharmony_ci } else { 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need " 5018c2ecf20Sopenharmony_ci "ACK (%d,%d,%d)\n", 5028c2ecf20Sopenharmony_ci cmd, wfcmd->action, wfcmd->read_cnt, 5038c2ecf20Sopenharmony_ci wfcmd->write_cnt, wfcmd->need_ack); 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci/*********************************************************************** 5118c2ecf20Sopenharmony_ciWaveFront data munging 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciThings here are weird. All data written to the board cannot 5148c2ecf20Sopenharmony_cihave its most significant bit set. Any data item with values 5158c2ecf20Sopenharmony_cipotentially > 0x7F (127) must be split across multiple bytes. 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ciSometimes, we need to munge numeric values that are represented on 5188c2ecf20Sopenharmony_cithe x86 side as 8-32 bit values. Sometimes, we need to munge data 5198c2ecf20Sopenharmony_cithat is represented on the x86 side as an array of bytes. The most 5208c2ecf20Sopenharmony_ciefficient approach to handling both cases seems to be to use 2 5218c2ecf20Sopenharmony_cidifferent functions for munging and 2 for de-munging. This avoids 5228c2ecf20Sopenharmony_ciweird casting and worrying about bit-level offsets. 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci**********************************************************************/ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic unsigned char * 5278c2ecf20Sopenharmony_cimunge_int32 (unsigned int src, 5288c2ecf20Sopenharmony_ci unsigned char *dst, 5298c2ecf20Sopenharmony_ci unsigned int dst_size) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci unsigned int i; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci for (i = 0; i < dst_size; i++) { 5348c2ecf20Sopenharmony_ci *dst = src & 0x7F; /* Mask high bit of LSB */ 5358c2ecf20Sopenharmony_ci src = src >> 7; /* Rotate Right 7 bits */ 5368c2ecf20Sopenharmony_ci /* Note: we leave the upper bits in place */ 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci dst++; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci return dst; 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int 5448c2ecf20Sopenharmony_cidemunge_int32 (unsigned char* src, int src_size) 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci int i; 5488c2ecf20Sopenharmony_ci int outval = 0; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci for (i = src_size - 1; i >= 0; i--) { 5518c2ecf20Sopenharmony_ci outval=(outval<<7)+src[i]; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return outval; 5558c2ecf20Sopenharmony_ci}; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic 5588c2ecf20Sopenharmony_ciunsigned char * 5598c2ecf20Sopenharmony_cimunge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size) 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci unsigned int i; 5638c2ecf20Sopenharmony_ci unsigned int last = dst_size / 2; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci for (i = 0; i < last; i++) { 5668c2ecf20Sopenharmony_ci *dst++ = src[i] & 0x7f; 5678c2ecf20Sopenharmony_ci *dst++ = src[i] >> 7; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci return dst; 5708c2ecf20Sopenharmony_ci} 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic 5738c2ecf20Sopenharmony_ciunsigned char * 5748c2ecf20Sopenharmony_cidemunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci int i; 5788c2ecf20Sopenharmony_ci unsigned char *end = src + src_bytes; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci end = src + src_bytes; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* NOTE: src and dst *CAN* point to the same address */ 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci for (i = 0; src != end; i++) { 5858c2ecf20Sopenharmony_ci dst[i] = *src++; 5868c2ecf20Sopenharmony_ci dst[i] |= (*src++)<<7; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return dst; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/*********************************************************************** 5938c2ecf20Sopenharmony_ciWaveFront: sample, patch and program management. 5948c2ecf20Sopenharmony_ci***********************************************************************/ 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic int 5978c2ecf20Sopenharmony_ciwavefront_delete_sample (snd_wavefront_t *dev, int sample_num) 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci unsigned char wbuf[2]; 6018c2ecf20Sopenharmony_ci int x; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci wbuf[0] = sample_num & 0x7f; 6048c2ecf20Sopenharmony_ci wbuf[1] = sample_num >> 7; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if ((x = snd_wavefront_cmd (dev, WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { 6078c2ecf20Sopenharmony_ci dev->sample_status[sample_num] = WF_ST_EMPTY; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return x; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int 6148c2ecf20Sopenharmony_ciwavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom) 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci int i; 6188c2ecf20Sopenharmony_ci unsigned char rbuf[32], wbuf[32]; 6198c2ecf20Sopenharmony_ci unsigned int sc_real, sc_alias, sc_multi; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci /* check sample status */ 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_GET_NSAMPLES, rbuf, wbuf)) { 6248c2ecf20Sopenharmony_ci snd_printk ("cannot request sample count.\n"); 6258c2ecf20Sopenharmony_ci return -1; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci sc_real = sc_alias = sc_multi = dev->samples_used = 0; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci for (i = 0; i < WF_MAX_SAMPLE; i++) { 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci wbuf[0] = i & 0x7f; 6338c2ecf20Sopenharmony_ci wbuf[1] = i >> 7; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { 6368c2ecf20Sopenharmony_ci snd_printk(KERN_WARNING "cannot identify sample " 6378c2ecf20Sopenharmony_ci "type of slot %d\n", i); 6388c2ecf20Sopenharmony_ci dev->sample_status[i] = WF_ST_EMPTY; 6398c2ecf20Sopenharmony_ci continue; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci dev->sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (assume_rom) { 6458c2ecf20Sopenharmony_ci dev->sample_status[i] |= WF_SLOT_ROM; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (rbuf[0] & WF_ST_MASK) { 6498c2ecf20Sopenharmony_ci case WF_ST_SAMPLE: 6508c2ecf20Sopenharmony_ci sc_real++; 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case WF_ST_MULTISAMPLE: 6538c2ecf20Sopenharmony_ci sc_multi++; 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci case WF_ST_ALIAS: 6568c2ecf20Sopenharmony_ci sc_alias++; 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci case WF_ST_EMPTY: 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci default: 6628c2ecf20Sopenharmony_ci snd_printk ("unknown sample type for " 6638c2ecf20Sopenharmony_ci "slot %d (0x%x)\n", 6648c2ecf20Sopenharmony_ci i, rbuf[0]); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci if (rbuf[0] != WF_ST_EMPTY) { 6688c2ecf20Sopenharmony_ci dev->samples_used++; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci snd_printk ("%d samples used (%d real, %d aliases, %d multi), " 6738c2ecf20Sopenharmony_ci "%d empty\n", dev->samples_used, sc_real, sc_alias, sc_multi, 6748c2ecf20Sopenharmony_ci WF_MAX_SAMPLE - dev->samples_used); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return (0); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_cistatic int 6828c2ecf20Sopenharmony_ciwavefront_get_patch_status (snd_wavefront_t *dev) 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci unsigned char patchbuf[WF_PATCH_BYTES]; 6868c2ecf20Sopenharmony_ci unsigned char patchnum[2]; 6878c2ecf20Sopenharmony_ci wavefront_patch *p; 6888c2ecf20Sopenharmony_ci int i, x, cnt, cnt2; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci for (i = 0; i < WF_MAX_PATCH; i++) { 6918c2ecf20Sopenharmony_ci patchnum[0] = i & 0x7f; 6928c2ecf20Sopenharmony_ci patchnum[1] = i >> 7; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PATCH, patchbuf, 6958c2ecf20Sopenharmony_ci patchnum)) == 0) { 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci dev->patch_status[i] |= WF_SLOT_FILLED; 6988c2ecf20Sopenharmony_ci p = (wavefront_patch *) patchbuf; 6998c2ecf20Sopenharmony_ci dev->sample_status 7008c2ecf20Sopenharmony_ci [p->sample_number|(p->sample_msb<<7)] |= 7018c2ecf20Sopenharmony_ci WF_SLOT_USED; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci } else if (x == 3) { /* Bad patch number */ 7048c2ecf20Sopenharmony_ci dev->patch_status[i] = 0; 7058c2ecf20Sopenharmony_ci } else { 7068c2ecf20Sopenharmony_ci snd_printk ("upload patch " 7078c2ecf20Sopenharmony_ci "error 0x%x\n", x); 7088c2ecf20Sopenharmony_ci dev->patch_status[i] = 0; 7098c2ecf20Sopenharmony_ci return 1; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* program status has already filled in slot_used bits */ 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { 7168c2ecf20Sopenharmony_ci if (dev->patch_status[i] & WF_SLOT_FILLED) { 7178c2ecf20Sopenharmony_ci cnt++; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci if (dev->patch_status[i] & WF_SLOT_USED) { 7208c2ecf20Sopenharmony_ci cnt2++; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci snd_printk ("%d patch slots filled, %d in use\n", cnt, cnt2); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return (0); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic int 7308c2ecf20Sopenharmony_ciwavefront_get_program_status (snd_wavefront_t *dev) 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci unsigned char progbuf[WF_PROGRAM_BYTES]; 7348c2ecf20Sopenharmony_ci wavefront_program prog; 7358c2ecf20Sopenharmony_ci unsigned char prognum; 7368c2ecf20Sopenharmony_ci int i, x, l, cnt; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci for (i = 0; i < WF_MAX_PROGRAM; i++) { 7398c2ecf20Sopenharmony_ci prognum = i; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PROGRAM, progbuf, 7428c2ecf20Sopenharmony_ci &prognum)) == 0) { 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci dev->prog_status[i] |= WF_SLOT_USED; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci demunge_buf (progbuf, (unsigned char *) &prog, 7478c2ecf20Sopenharmony_ci WF_PROGRAM_BYTES); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci for (l = 0; l < WF_NUM_LAYERS; l++) { 7508c2ecf20Sopenharmony_ci if (prog.layer[l].mute) { 7518c2ecf20Sopenharmony_ci dev->patch_status 7528c2ecf20Sopenharmony_ci [prog.layer[l].patch_number] |= 7538c2ecf20Sopenharmony_ci WF_SLOT_USED; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci } else if (x == 1) { /* Bad program number */ 7578c2ecf20Sopenharmony_ci dev->prog_status[i] = 0; 7588c2ecf20Sopenharmony_ci } else { 7598c2ecf20Sopenharmony_ci snd_printk ("upload program " 7608c2ecf20Sopenharmony_ci "error 0x%x\n", x); 7618c2ecf20Sopenharmony_ci dev->prog_status[i] = 0; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { 7668c2ecf20Sopenharmony_ci if (dev->prog_status[i]) { 7678c2ecf20Sopenharmony_ci cnt++; 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci snd_printk ("%d programs slots in use\n", cnt); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return (0); 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int 7778c2ecf20Sopenharmony_ciwavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header) 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci unsigned char buf[WF_PATCH_BYTES+2]; 7818c2ecf20Sopenharmony_ci unsigned char *bptr; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", 7848c2ecf20Sopenharmony_ci header->number); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (header->number >= ARRAY_SIZE(dev->patch_status)) 7878c2ecf20Sopenharmony_ci return -EINVAL; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci dev->patch_status[header->number] |= WF_SLOT_FILLED; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci bptr = munge_int32 (header->number, buf, 2); 7928c2ecf20Sopenharmony_ci munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) { 7958c2ecf20Sopenharmony_ci snd_printk ("download patch failed\n"); 7968c2ecf20Sopenharmony_ci return -EIO; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return (0); 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int 8038c2ecf20Sopenharmony_ciwavefront_send_program (snd_wavefront_t *dev, wavefront_patch_info *header) 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci unsigned char buf[WF_PROGRAM_BYTES+1]; 8078c2ecf20Sopenharmony_ci int i; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", 8108c2ecf20Sopenharmony_ci header->number); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (header->number >= ARRAY_SIZE(dev->prog_status)) 8138c2ecf20Sopenharmony_ci return -EINVAL; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci dev->prog_status[header->number] = WF_SLOT_USED; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* XXX need to zero existing SLOT_USED bit for program_status[i] 8188c2ecf20Sopenharmony_ci where `i' is the program that's being (potentially) overwritten. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci for (i = 0; i < WF_NUM_LAYERS; i++) { 8228c2ecf20Sopenharmony_ci if (header->hdr.pr.layer[i].mute) { 8238c2ecf20Sopenharmony_ci dev->patch_status[header->hdr.pr.layer[i].patch_number] |= 8248c2ecf20Sopenharmony_ci WF_SLOT_USED; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* XXX need to mark SLOT_USED for sample used by 8278c2ecf20Sopenharmony_ci patch_number, but this means we have to load it. Ick. 8288c2ecf20Sopenharmony_ci */ 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci buf[0] = header->number; 8338c2ecf20Sopenharmony_ci munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) { 8368c2ecf20Sopenharmony_ci snd_printk ("download patch failed\n"); 8378c2ecf20Sopenharmony_ci return -EIO; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci return (0); 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int 8448c2ecf20Sopenharmony_ciwavefront_freemem (snd_wavefront_t *dev) 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci char rbuf[8]; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { 8508c2ecf20Sopenharmony_ci snd_printk ("can't get memory stats.\n"); 8518c2ecf20Sopenharmony_ci return -1; 8528c2ecf20Sopenharmony_ci } else { 8538c2ecf20Sopenharmony_ci return demunge_int32 (rbuf, 4); 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int 8588c2ecf20Sopenharmony_ciwavefront_send_sample (snd_wavefront_t *dev, 8598c2ecf20Sopenharmony_ci wavefront_patch_info *header, 8608c2ecf20Sopenharmony_ci u16 __user *dataptr, 8618c2ecf20Sopenharmony_ci int data_is_unsigned) 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci /* samples are downloaded via a 16-bit wide i/o port 8658c2ecf20Sopenharmony_ci (you could think of it as 2 adjacent 8-bit wide ports 8668c2ecf20Sopenharmony_ci but its less efficient that way). therefore, all 8678c2ecf20Sopenharmony_ci the blocksizes and so forth listed in the documentation, 8688c2ecf20Sopenharmony_ci and used conventionally to refer to sample sizes, 8698c2ecf20Sopenharmony_ci which are given in 8-bit units (bytes), need to be 8708c2ecf20Sopenharmony_ci divided by 2. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci u16 sample_short = 0; 8748c2ecf20Sopenharmony_ci u32 length; 8758c2ecf20Sopenharmony_ci u16 __user *data_end = NULL; 8768c2ecf20Sopenharmony_ci unsigned int i; 8778c2ecf20Sopenharmony_ci const unsigned int max_blksize = 4096/2; 8788c2ecf20Sopenharmony_ci unsigned int written; 8798c2ecf20Sopenharmony_ci unsigned int blocksize; 8808c2ecf20Sopenharmony_ci int dma_ack; 8818c2ecf20Sopenharmony_ci int blocknum; 8828c2ecf20Sopenharmony_ci unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; 8838c2ecf20Sopenharmony_ci unsigned char *shptr; 8848c2ecf20Sopenharmony_ci int skip = 0; 8858c2ecf20Sopenharmony_ci int initial_skip = 0; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " 8888c2ecf20Sopenharmony_ci "type %d, %d bytes from 0x%lx\n", 8898c2ecf20Sopenharmony_ci header->size ? "" : "header ", 8908c2ecf20Sopenharmony_ci header->number, header->subkey, 8918c2ecf20Sopenharmony_ci header->size, 8928c2ecf20Sopenharmony_ci (unsigned long) header->dataptr); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { 8958c2ecf20Sopenharmony_ci int x; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if ((x = wavefront_find_free_sample (dev)) < 0) { 8988c2ecf20Sopenharmony_ci return -ENOMEM; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci snd_printk ("unspecified sample => %d\n", x); 9018c2ecf20Sopenharmony_ci header->number = x; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (header->number >= WF_MAX_SAMPLE) 9058c2ecf20Sopenharmony_ci return -EINVAL; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (header->size) { 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci /* XXX it's a debatable point whether or not RDONLY semantics 9108c2ecf20Sopenharmony_ci on the ROM samples should cover just the sample data or 9118c2ecf20Sopenharmony_ci the sample header. For now, it only covers the sample data, 9128c2ecf20Sopenharmony_ci so anyone is free at all times to rewrite sample headers. 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci My reason for this is that we have the sample headers 9158c2ecf20Sopenharmony_ci available in the WFB file for General MIDI, and so these 9168c2ecf20Sopenharmony_ci can always be reset if needed. The sample data, however, 9178c2ecf20Sopenharmony_ci cannot be recovered without a complete reset and firmware 9188c2ecf20Sopenharmony_ci reload of the ICS2115, which is a very expensive operation. 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci So, doing things this way allows us to honor the notion of 9218c2ecf20Sopenharmony_ci "RESETSAMPLES" reasonably cheaply. Note however, that this 9228c2ecf20Sopenharmony_ci is done purely at user level: there is no WFB parser in 9238c2ecf20Sopenharmony_ci this driver, and so a complete reset (back to General MIDI, 9248c2ecf20Sopenharmony_ci or theoretically some other configuration) is the 9258c2ecf20Sopenharmony_ci responsibility of the user level library. 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci To try to do this in the kernel would be a little 9288c2ecf20Sopenharmony_ci crazy: we'd need 158K of kernel space just to hold 9298c2ecf20Sopenharmony_ci a copy of the patch/program/sample header data. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (dev->rom_samples_rdonly) { 9338c2ecf20Sopenharmony_ci if (dev->sample_status[header->number] & WF_SLOT_ROM) { 9348c2ecf20Sopenharmony_ci snd_printk ("sample slot %d " 9358c2ecf20Sopenharmony_ci "write protected\n", 9368c2ecf20Sopenharmony_ci header->number); 9378c2ecf20Sopenharmony_ci return -EACCES; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci wavefront_delete_sample (dev, header->number); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (header->size) { 9458c2ecf20Sopenharmony_ci dev->freemem = wavefront_freemem (dev); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (dev->freemem < (int)header->size) { 9488c2ecf20Sopenharmony_ci snd_printk ("insufficient memory to " 9498c2ecf20Sopenharmony_ci "load %d byte sample.\n", 9508c2ecf20Sopenharmony_ci header->size); 9518c2ecf20Sopenharmony_ci return -ENOMEM; 9528c2ecf20Sopenharmony_ci } 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci skip = WF_GET_CHANNEL(&header->hdr.s); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { 9598c2ecf20Sopenharmony_ci snd_printk ("channel selection only " 9608c2ecf20Sopenharmony_ci "possible on 16-bit samples"); 9618c2ecf20Sopenharmony_ci return -EINVAL; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci switch (skip) { 9658c2ecf20Sopenharmony_ci case 0: 9668c2ecf20Sopenharmony_ci initial_skip = 0; 9678c2ecf20Sopenharmony_ci skip = 1; 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci case 1: 9708c2ecf20Sopenharmony_ci initial_skip = 0; 9718c2ecf20Sopenharmony_ci skip = 2; 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci case 2: 9748c2ecf20Sopenharmony_ci initial_skip = 1; 9758c2ecf20Sopenharmony_ci skip = 2; 9768c2ecf20Sopenharmony_ci break; 9778c2ecf20Sopenharmony_ci case 3: 9788c2ecf20Sopenharmony_ci initial_skip = 2; 9798c2ecf20Sopenharmony_ci skip = 3; 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci case 4: 9828c2ecf20Sopenharmony_ci initial_skip = 3; 9838c2ecf20Sopenharmony_ci skip = 4; 9848c2ecf20Sopenharmony_ci break; 9858c2ecf20Sopenharmony_ci case 5: 9868c2ecf20Sopenharmony_ci initial_skip = 4; 9878c2ecf20Sopenharmony_ci skip = 5; 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci case 6: 9908c2ecf20Sopenharmony_ci initial_skip = 5; 9918c2ecf20Sopenharmony_ci skip = 6; 9928c2ecf20Sopenharmony_ci break; 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " 9968c2ecf20Sopenharmony_ci "initial skip = %d, skip = %d\n", 9978c2ecf20Sopenharmony_ci WF_GET_CHANNEL (&header->hdr.s), 9988c2ecf20Sopenharmony_ci initial_skip, skip); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci /* Be safe, and zero the "Unused" bits ... */ 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci WF_SET_CHANNEL(&header->hdr.s, 0); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* adjust size for 16 bit samples by dividing by two. We always 10058c2ecf20Sopenharmony_ci send 16 bits per write, even for 8 bit samples, so the length 10068c2ecf20Sopenharmony_ci is always half the size of the sample data in bytes. 10078c2ecf20Sopenharmony_ci */ 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci length = header->size / 2; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* the data we're sent has not been munged, and in fact, the 10128c2ecf20Sopenharmony_ci header we have to send isn't just a munged copy either. 10138c2ecf20Sopenharmony_ci so, build the sample header right here. 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci shptr = &sample_hdr[0]; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci shptr = munge_int32 (header->number, shptr, 2); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (header->size) { 10218c2ecf20Sopenharmony_ci shptr = munge_int32 (length, shptr, 4); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* Yes, a 4 byte result doesn't contain all of the offset bits, 10258c2ecf20Sopenharmony_ci but the offset only uses 24 bits. 10268c2ecf20Sopenharmony_ci */ 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleStartOffset), 10298c2ecf20Sopenharmony_ci shptr, 4); 10308c2ecf20Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.loopStartOffset), 10318c2ecf20Sopenharmony_ci shptr, 4); 10328c2ecf20Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.loopEndOffset), 10338c2ecf20Sopenharmony_ci shptr, 4); 10348c2ecf20Sopenharmony_ci shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleEndOffset), 10358c2ecf20Sopenharmony_ci shptr, 4); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* This one is truly weird. What kind of weirdo decided that in 10388c2ecf20Sopenharmony_ci a system dominated by 16 and 32 bit integers, they would use 10398c2ecf20Sopenharmony_ci a just 12 bits ? 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci /* Why is this nybblified, when the MSB is *always* zero ? 10458c2ecf20Sopenharmony_ci Anyway, we can't take address of bitfield, so make a 10468c2ecf20Sopenharmony_ci good-faith guess at where it starts. 10478c2ecf20Sopenharmony_ci */ 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), 10508c2ecf20Sopenharmony_ci shptr, 2); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, 10538c2ecf20Sopenharmony_ci header->size ? 10548c2ecf20Sopenharmony_ci WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, 10558c2ecf20Sopenharmony_ci NULL, sample_hdr)) { 10568c2ecf20Sopenharmony_ci snd_printk ("sample %sdownload refused.\n", 10578c2ecf20Sopenharmony_ci header->size ? "" : "header "); 10588c2ecf20Sopenharmony_ci return -EIO; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (header->size == 0) { 10628c2ecf20Sopenharmony_ci goto sent; /* Sorry. Just had to have one somewhere */ 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci data_end = dataptr + length; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* Do any initial skip over an unused channel's data */ 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci dataptr += initial_skip; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci for (written = 0, blocknum = 0; 10728c2ecf20Sopenharmony_ci written < length; written += max_blksize, blocknum++) { 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if ((length - written) > max_blksize) { 10758c2ecf20Sopenharmony_ci blocksize = max_blksize; 10768c2ecf20Sopenharmony_ci } else { 10778c2ecf20Sopenharmony_ci /* round to nearest 16-byte value */ 10788c2ecf20Sopenharmony_ci blocksize = ALIGN(length - written, 8); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) { 10828c2ecf20Sopenharmony_ci snd_printk ("download block " 10838c2ecf20Sopenharmony_ci "request refused.\n"); 10848c2ecf20Sopenharmony_ci return -EIO; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci for (i = 0; i < blocksize; i++) { 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci if (dataptr < data_end) { 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (get_user(sample_short, dataptr)) 10928c2ecf20Sopenharmony_ci return -EFAULT; 10938c2ecf20Sopenharmony_ci dataptr += skip; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (data_is_unsigned) { /* GUS ? */ 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci /* 8 bit sample 11008c2ecf20Sopenharmony_ci resolution, sign 11018c2ecf20Sopenharmony_ci extend both bytes. 11028c2ecf20Sopenharmony_ci */ 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci ((unsigned char*) 11058c2ecf20Sopenharmony_ci &sample_short)[0] += 0x7f; 11068c2ecf20Sopenharmony_ci ((unsigned char*) 11078c2ecf20Sopenharmony_ci &sample_short)[1] += 0x7f; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci } else { 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* 16 bit sample 11128c2ecf20Sopenharmony_ci resolution, sign 11138c2ecf20Sopenharmony_ci extend the MSB. 11148c2ecf20Sopenharmony_ci */ 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci sample_short += 0x7fff; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci } else { 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* In padding section of final block: 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci Don't fetch unsupplied data from 11258c2ecf20Sopenharmony_ci user space, just continue with 11268c2ecf20Sopenharmony_ci whatever the final value was. 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci } 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci if (i < blocksize - 1) { 11318c2ecf20Sopenharmony_ci outw (sample_short, dev->block_port); 11328c2ecf20Sopenharmony_ci } else { 11338c2ecf20Sopenharmony_ci outw (sample_short, dev->last_block_port); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* Get "DMA page acknowledge", even though its really 11388c2ecf20Sopenharmony_ci nothing to do with DMA at all. 11398c2ecf20Sopenharmony_ci */ 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if ((dma_ack = wavefront_read (dev)) != WF_DMA_ACK) { 11428c2ecf20Sopenharmony_ci if (dma_ack == -1) { 11438c2ecf20Sopenharmony_ci snd_printk ("upload sample " 11448c2ecf20Sopenharmony_ci "DMA ack timeout\n"); 11458c2ecf20Sopenharmony_ci return -EIO; 11468c2ecf20Sopenharmony_ci } else { 11478c2ecf20Sopenharmony_ci snd_printk ("upload sample " 11488c2ecf20Sopenharmony_ci "DMA ack error 0x%x\n", 11498c2ecf20Sopenharmony_ci dma_ack); 11508c2ecf20Sopenharmony_ci return -EIO; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci /* Note, label is here because sending the sample header shouldn't 11588c2ecf20Sopenharmony_ci alter the sample_status info at all. 11598c2ecf20Sopenharmony_ci */ 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci sent: 11628c2ecf20Sopenharmony_ci return (0); 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic int 11668c2ecf20Sopenharmony_ciwavefront_send_alias (snd_wavefront_t *dev, wavefront_patch_info *header) 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci unsigned char alias_hdr[WF_ALIAS_BYTES]; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is " 11728c2ecf20Sopenharmony_ci "alias for %d\n", 11738c2ecf20Sopenharmony_ci header->number, 11748c2ecf20Sopenharmony_ci header->hdr.a.OriginalSample); 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (header->number >= WF_MAX_SAMPLE) 11778c2ecf20Sopenharmony_ci return -EINVAL; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci munge_int32 (header->number, &alias_hdr[0], 2); 11808c2ecf20Sopenharmony_ci munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); 11818c2ecf20Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset), 11828c2ecf20Sopenharmony_ci &alias_hdr[4], 4); 11838c2ecf20Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset), 11848c2ecf20Sopenharmony_ci &alias_hdr[8], 4); 11858c2ecf20Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset), 11868c2ecf20Sopenharmony_ci &alias_hdr[12], 4); 11878c2ecf20Sopenharmony_ci munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset), 11888c2ecf20Sopenharmony_ci &alias_hdr[16], 4); 11898c2ecf20Sopenharmony_ci munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3); 11908c2ecf20Sopenharmony_ci munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { 11938c2ecf20Sopenharmony_ci snd_printk ("download alias failed.\n"); 11948c2ecf20Sopenharmony_ci return -EIO; 11958c2ecf20Sopenharmony_ci } 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci return (0); 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_cistatic int 12038c2ecf20Sopenharmony_ciwavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci int i; 12068c2ecf20Sopenharmony_ci int num_samples; 12078c2ecf20Sopenharmony_ci unsigned char *msample_hdr; 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (header->number >= WF_MAX_SAMPLE) 12108c2ecf20Sopenharmony_ci return -EINVAL; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci msample_hdr = kmalloc(WF_MSAMPLE_BYTES, GFP_KERNEL); 12138c2ecf20Sopenharmony_ci if (! msample_hdr) 12148c2ecf20Sopenharmony_ci return -ENOMEM; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci munge_int32 (header->number, &msample_hdr[0], 2); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* You'll recall at this point that the "number of samples" value 12198c2ecf20Sopenharmony_ci in a wavefront_multisample struct is actually the log2 of the 12208c2ecf20Sopenharmony_ci real number of samples. 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); 12248c2ecf20Sopenharmony_ci msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n", 12278c2ecf20Sopenharmony_ci header->number, 12288c2ecf20Sopenharmony_ci header->hdr.ms.NumberOfSamples, 12298c2ecf20Sopenharmony_ci num_samples); 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci for (i = 0; i < num_samples; i++) { 12328c2ecf20Sopenharmony_ci DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n", 12338c2ecf20Sopenharmony_ci i, header->hdr.ms.SampleNumber[i]); 12348c2ecf20Sopenharmony_ci munge_int32 (header->hdr.ms.SampleNumber[i], 12358c2ecf20Sopenharmony_ci &msample_hdr[3+(i*2)], 2); 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* Need a hack here to pass in the number of bytes 12398c2ecf20Sopenharmony_ci to be written to the synth. This is ugly, and perhaps 12408c2ecf20Sopenharmony_ci one day, I'll fix it. 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE, 12448c2ecf20Sopenharmony_ci (unsigned char *) (long) ((num_samples*2)+3), 12458c2ecf20Sopenharmony_ci msample_hdr)) { 12468c2ecf20Sopenharmony_ci snd_printk ("download of multisample failed.\n"); 12478c2ecf20Sopenharmony_ci kfree(msample_hdr); 12488c2ecf20Sopenharmony_ci return -EIO; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci kfree(msample_hdr); 12548c2ecf20Sopenharmony_ci return (0); 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int 12588c2ecf20Sopenharmony_ciwavefront_fetch_multisample (snd_wavefront_t *dev, 12598c2ecf20Sopenharmony_ci wavefront_patch_info *header) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci int i; 12628c2ecf20Sopenharmony_ci unsigned char log_ns[1]; 12638c2ecf20Sopenharmony_ci unsigned char number[2]; 12648c2ecf20Sopenharmony_ci int num_samples; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci munge_int32 (header->number, number, 2); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { 12698c2ecf20Sopenharmony_ci snd_printk ("upload multisample failed.\n"); 12708c2ecf20Sopenharmony_ci return -EIO; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n", 12748c2ecf20Sopenharmony_ci header->number, log_ns[0]); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci header->hdr.ms.NumberOfSamples = log_ns[0]; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* get the number of samples ... */ 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci num_samples = (1 << log_ns[0]); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci for (i = 0; i < num_samples; i++) { 12838c2ecf20Sopenharmony_ci char d[2]; 12848c2ecf20Sopenharmony_ci int val; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if ((val = wavefront_read (dev)) == -1) { 12878c2ecf20Sopenharmony_ci snd_printk ("upload multisample failed " 12888c2ecf20Sopenharmony_ci "during sample loop.\n"); 12898c2ecf20Sopenharmony_ci return -EIO; 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci d[0] = val; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if ((val = wavefront_read (dev)) == -1) { 12948c2ecf20Sopenharmony_ci snd_printk ("upload multisample failed " 12958c2ecf20Sopenharmony_ci "during sample loop.\n"); 12968c2ecf20Sopenharmony_ci return -EIO; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci d[1] = val; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci header->hdr.ms.SampleNumber[i] = 13018c2ecf20Sopenharmony_ci demunge_int32 ((unsigned char *) d, 2); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n", 13048c2ecf20Sopenharmony_ci i, header->hdr.ms.SampleNumber[i]); 13058c2ecf20Sopenharmony_ci } 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci return (0); 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_cistatic int 13128c2ecf20Sopenharmony_ciwavefront_send_drum (snd_wavefront_t *dev, wavefront_patch_info *header) 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci unsigned char drumbuf[WF_DRUM_BYTES]; 13168c2ecf20Sopenharmony_ci wavefront_drum *drum = &header->hdr.d; 13178c2ecf20Sopenharmony_ci int i; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI " 13208c2ecf20Sopenharmony_ci "note %d, patch = %d\n", 13218c2ecf20Sopenharmony_ci header->number, drum->PatchNumber); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci drumbuf[0] = header->number & 0x7f; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 13268c2ecf20Sopenharmony_ci munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2); 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { 13308c2ecf20Sopenharmony_ci snd_printk ("download drum failed.\n"); 13318c2ecf20Sopenharmony_ci return -EIO; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci return (0); 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic int 13388c2ecf20Sopenharmony_ciwavefront_find_free_sample (snd_wavefront_t *dev) 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci int i; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci for (i = 0; i < WF_MAX_SAMPLE; i++) { 13448c2ecf20Sopenharmony_ci if (!(dev->sample_status[i] & WF_SLOT_FILLED)) { 13458c2ecf20Sopenharmony_ci return i; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci snd_printk ("no free sample slots!\n"); 13498c2ecf20Sopenharmony_ci return -1; 13508c2ecf20Sopenharmony_ci} 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci#if 0 13538c2ecf20Sopenharmony_cistatic int 13548c2ecf20Sopenharmony_ciwavefront_find_free_patch (snd_wavefront_t *dev) 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci int i; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci for (i = 0; i < WF_MAX_PATCH; i++) { 13608c2ecf20Sopenharmony_ci if (!(dev->patch_status[i] & WF_SLOT_FILLED)) { 13618c2ecf20Sopenharmony_ci return i; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci snd_printk ("no free patch slots!\n"); 13658c2ecf20Sopenharmony_ci return -1; 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci#endif 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int 13708c2ecf20Sopenharmony_ciwavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci wavefront_patch_info *header; 13738c2ecf20Sopenharmony_ci int err; 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci header = kmalloc(sizeof(*header), GFP_KERNEL); 13768c2ecf20Sopenharmony_ci if (! header) 13778c2ecf20Sopenharmony_ci return -ENOMEM; 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (copy_from_user (header, addr, sizeof(wavefront_patch_info) - 13808c2ecf20Sopenharmony_ci sizeof(wavefront_any))) { 13818c2ecf20Sopenharmony_ci snd_printk ("bad address for load patch.\n"); 13828c2ecf20Sopenharmony_ci err = -EFAULT; 13838c2ecf20Sopenharmony_ci goto __error; 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_LOAD_PATCH, "download " 13878c2ecf20Sopenharmony_ci "Sample type: %d " 13888c2ecf20Sopenharmony_ci "Sample number: %d " 13898c2ecf20Sopenharmony_ci "Sample size: %d\n", 13908c2ecf20Sopenharmony_ci header->subkey, 13918c2ecf20Sopenharmony_ci header->number, 13928c2ecf20Sopenharmony_ci header->size); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci switch (header->subkey) { 13958c2ecf20Sopenharmony_ci case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (copy_from_user (&header->hdr.s, header->hdrptr, 13988c2ecf20Sopenharmony_ci sizeof (wavefront_sample))) { 13998c2ecf20Sopenharmony_ci err = -EFAULT; 14008c2ecf20Sopenharmony_ci break; 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci err = wavefront_send_sample (dev, header, header->dataptr, 0); 14048c2ecf20Sopenharmony_ci break; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci case WF_ST_MULTISAMPLE: 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (copy_from_user (&header->hdr.s, header->hdrptr, 14098c2ecf20Sopenharmony_ci sizeof (wavefront_multisample))) { 14108c2ecf20Sopenharmony_ci err = -EFAULT; 14118c2ecf20Sopenharmony_ci break; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci err = wavefront_send_multisample (dev, header); 14158c2ecf20Sopenharmony_ci break; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci case WF_ST_ALIAS: 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (copy_from_user (&header->hdr.a, header->hdrptr, 14208c2ecf20Sopenharmony_ci sizeof (wavefront_alias))) { 14218c2ecf20Sopenharmony_ci err = -EFAULT; 14228c2ecf20Sopenharmony_ci break; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci err = wavefront_send_alias (dev, header); 14268c2ecf20Sopenharmony_ci break; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci case WF_ST_DRUM: 14298c2ecf20Sopenharmony_ci if (copy_from_user (&header->hdr.d, header->hdrptr, 14308c2ecf20Sopenharmony_ci sizeof (wavefront_drum))) { 14318c2ecf20Sopenharmony_ci err = -EFAULT; 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci err = wavefront_send_drum (dev, header); 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci case WF_ST_PATCH: 14398c2ecf20Sopenharmony_ci if (copy_from_user (&header->hdr.p, header->hdrptr, 14408c2ecf20Sopenharmony_ci sizeof (wavefront_patch))) { 14418c2ecf20Sopenharmony_ci err = -EFAULT; 14428c2ecf20Sopenharmony_ci break; 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci err = wavefront_send_patch (dev, header); 14468c2ecf20Sopenharmony_ci break; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci case WF_ST_PROGRAM: 14498c2ecf20Sopenharmony_ci if (copy_from_user (&header->hdr.pr, header->hdrptr, 14508c2ecf20Sopenharmony_ci sizeof (wavefront_program))) { 14518c2ecf20Sopenharmony_ci err = -EFAULT; 14528c2ecf20Sopenharmony_ci break; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci err = wavefront_send_program (dev, header); 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci default: 14598c2ecf20Sopenharmony_ci snd_printk ("unknown patch type %d.\n", 14608c2ecf20Sopenharmony_ci header->subkey); 14618c2ecf20Sopenharmony_ci err = -EINVAL; 14628c2ecf20Sopenharmony_ci break; 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci __error: 14668c2ecf20Sopenharmony_ci kfree(header); 14678c2ecf20Sopenharmony_ci return err; 14688c2ecf20Sopenharmony_ci} 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci/*********************************************************************** 14718c2ecf20Sopenharmony_ciWaveFront: hardware-dependent interface 14728c2ecf20Sopenharmony_ci***********************************************************************/ 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic void 14758c2ecf20Sopenharmony_ciprocess_sample_hdr (u8 *buf) 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci wavefront_sample s; 14798c2ecf20Sopenharmony_ci u8 *ptr; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci ptr = buf; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* The board doesn't send us an exact copy of a "wavefront_sample" 14848c2ecf20Sopenharmony_ci in response to an Upload Sample Header command. Instead, we 14858c2ecf20Sopenharmony_ci have to convert the data format back into our data structure, 14868c2ecf20Sopenharmony_ci just as in the Download Sample command, where we have to do 14878c2ecf20Sopenharmony_ci something very similar in the reverse direction. 14888c2ecf20Sopenharmony_ci */ 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci *((u32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; 14918c2ecf20Sopenharmony_ci *((u32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; 14928c2ecf20Sopenharmony_ci *((u32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; 14938c2ecf20Sopenharmony_ci *((u32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; 14948c2ecf20Sopenharmony_ci *((u32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci s.SampleResolution = *ptr & 0x3; 14978c2ecf20Sopenharmony_ci s.Loop = *ptr & 0x8; 14988c2ecf20Sopenharmony_ci s.Bidirectional = *ptr & 0x10; 14998c2ecf20Sopenharmony_ci s.Reverse = *ptr & 0x40; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* Now copy it back to where it came from */ 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample)); 15048c2ecf20Sopenharmony_ci} 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_cistatic int 15078c2ecf20Sopenharmony_ciwavefront_synth_control (snd_wavefront_card_t *acard, 15088c2ecf20Sopenharmony_ci wavefront_control *wc) 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci{ 15118c2ecf20Sopenharmony_ci snd_wavefront_t *dev = &acard->wavefront; 15128c2ecf20Sopenharmony_ci unsigned char patchnumbuf[2]; 15138c2ecf20Sopenharmony_ci int i; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci DPRINT (WF_DEBUG_CMD, "synth control with " 15168c2ecf20Sopenharmony_ci "cmd 0x%x\n", wc->cmd); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci /* Pre-handling of or for various commands */ 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci switch (wc->cmd) { 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci case WFC_DISABLE_INTERRUPTS: 15238c2ecf20Sopenharmony_ci snd_printk ("interrupts disabled.\n"); 15248c2ecf20Sopenharmony_ci outb (0x80|0x20, dev->control_port); 15258c2ecf20Sopenharmony_ci dev->interrupts_are_midi = 1; 15268c2ecf20Sopenharmony_ci return 0; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci case WFC_ENABLE_INTERRUPTS: 15298c2ecf20Sopenharmony_ci snd_printk ("interrupts enabled.\n"); 15308c2ecf20Sopenharmony_ci outb (0x80|0x40|0x20, dev->control_port); 15318c2ecf20Sopenharmony_ci dev->interrupts_are_midi = 1; 15328c2ecf20Sopenharmony_ci return 0; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci case WFC_INTERRUPT_STATUS: 15358c2ecf20Sopenharmony_ci wc->rbuf[0] = dev->interrupts_are_midi; 15368c2ecf20Sopenharmony_ci return 0; 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci case WFC_ROMSAMPLES_RDONLY: 15398c2ecf20Sopenharmony_ci dev->rom_samples_rdonly = wc->wbuf[0]; 15408c2ecf20Sopenharmony_ci wc->status = 0; 15418c2ecf20Sopenharmony_ci return 0; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci case WFC_IDENTIFY_SLOT_TYPE: 15448c2ecf20Sopenharmony_ci i = wc->wbuf[0] | (wc->wbuf[1] << 7); 15458c2ecf20Sopenharmony_ci if (i <0 || i >= WF_MAX_SAMPLE) { 15468c2ecf20Sopenharmony_ci snd_printk ("invalid slot ID %d\n", 15478c2ecf20Sopenharmony_ci i); 15488c2ecf20Sopenharmony_ci wc->status = EINVAL; 15498c2ecf20Sopenharmony_ci return -EINVAL; 15508c2ecf20Sopenharmony_ci } 15518c2ecf20Sopenharmony_ci wc->rbuf[0] = dev->sample_status[i]; 15528c2ecf20Sopenharmony_ci wc->status = 0; 15538c2ecf20Sopenharmony_ci return 0; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci case WFC_DEBUG_DRIVER: 15568c2ecf20Sopenharmony_ci dev->debug = wc->wbuf[0]; 15578c2ecf20Sopenharmony_ci snd_printk ("debug = 0x%x\n", dev->debug); 15588c2ecf20Sopenharmony_ci return 0; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci case WFC_UPLOAD_PATCH: 15618c2ecf20Sopenharmony_ci munge_int32 (*((u32 *) wc->wbuf), patchnumbuf, 2); 15628c2ecf20Sopenharmony_ci memcpy (wc->wbuf, patchnumbuf, 2); 15638c2ecf20Sopenharmony_ci break; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci case WFC_UPLOAD_MULTISAMPLE: 15668c2ecf20Sopenharmony_ci /* multisamples have to be handled differently, and 15678c2ecf20Sopenharmony_ci cannot be dealt with properly by snd_wavefront_cmd() alone. 15688c2ecf20Sopenharmony_ci */ 15698c2ecf20Sopenharmony_ci wc->status = wavefront_fetch_multisample 15708c2ecf20Sopenharmony_ci (dev, (wavefront_patch_info *) wc->rbuf); 15718c2ecf20Sopenharmony_ci return 0; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci case WFC_UPLOAD_SAMPLE_ALIAS: 15748c2ecf20Sopenharmony_ci snd_printk ("support for sample alias upload " 15758c2ecf20Sopenharmony_ci "being considered.\n"); 15768c2ecf20Sopenharmony_ci wc->status = EINVAL; 15778c2ecf20Sopenharmony_ci return -EINVAL; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci wc->status = snd_wavefront_cmd (dev, wc->cmd, wc->rbuf, wc->wbuf); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* Post-handling of certain commands. 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci In particular, if the command was an upload, demunge the data 15858c2ecf20Sopenharmony_ci so that the user-level doesn't have to think about it. 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (wc->status == 0) { 15898c2ecf20Sopenharmony_ci switch (wc->cmd) { 15908c2ecf20Sopenharmony_ci /* intercept any freemem requests so that we know 15918c2ecf20Sopenharmony_ci we are always current with the user-level view 15928c2ecf20Sopenharmony_ci of things. 15938c2ecf20Sopenharmony_ci */ 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci case WFC_REPORT_FREE_MEMORY: 15968c2ecf20Sopenharmony_ci dev->freemem = demunge_int32 (wc->rbuf, 4); 15978c2ecf20Sopenharmony_ci break; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci case WFC_UPLOAD_PATCH: 16008c2ecf20Sopenharmony_ci demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci case WFC_UPLOAD_PROGRAM: 16048c2ecf20Sopenharmony_ci demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci case WFC_UPLOAD_EDRUM_PROGRAM: 16088c2ecf20Sopenharmony_ci demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); 16098c2ecf20Sopenharmony_ci break; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci case WFC_UPLOAD_SAMPLE_HEADER: 16128c2ecf20Sopenharmony_ci process_sample_hdr (wc->rbuf); 16138c2ecf20Sopenharmony_ci break; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci case WFC_UPLOAD_SAMPLE_ALIAS: 16168c2ecf20Sopenharmony_ci snd_printk ("support for " 16178c2ecf20Sopenharmony_ci "sample aliases still " 16188c2ecf20Sopenharmony_ci "being considered.\n"); 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci case WFC_VMIDI_OFF: 16228c2ecf20Sopenharmony_ci snd_wavefront_midi_disable_virtual (acard); 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci case WFC_VMIDI_ON: 16268c2ecf20Sopenharmony_ci snd_wavefront_midi_enable_virtual (acard); 16278c2ecf20Sopenharmony_ci break; 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci return 0; 16328c2ecf20Sopenharmony_ci} 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ciint 16358c2ecf20Sopenharmony_cisnd_wavefront_synth_open (struct snd_hwdep *hw, struct file *file) 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci if (!try_module_get(hw->card->module)) 16398c2ecf20Sopenharmony_ci return -EFAULT; 16408c2ecf20Sopenharmony_ci file->private_data = hw; 16418c2ecf20Sopenharmony_ci return 0; 16428c2ecf20Sopenharmony_ci} 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ciint 16458c2ecf20Sopenharmony_cisnd_wavefront_synth_release (struct snd_hwdep *hw, struct file *file) 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci{ 16488c2ecf20Sopenharmony_ci module_put(hw->card->module); 16498c2ecf20Sopenharmony_ci return 0; 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ciint 16538c2ecf20Sopenharmony_cisnd_wavefront_synth_ioctl (struct snd_hwdep *hw, struct file *file, 16548c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci struct snd_card *card; 16588c2ecf20Sopenharmony_ci snd_wavefront_t *dev; 16598c2ecf20Sopenharmony_ci snd_wavefront_card_t *acard; 16608c2ecf20Sopenharmony_ci wavefront_control *wc; 16618c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 16628c2ecf20Sopenharmony_ci int err; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci card = (struct snd_card *) hw->card; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci if (snd_BUG_ON(!card)) 16678c2ecf20Sopenharmony_ci return -ENODEV; 16688c2ecf20Sopenharmony_ci if (snd_BUG_ON(!card->private_data)) 16698c2ecf20Sopenharmony_ci return -ENODEV; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci acard = card->private_data; 16728c2ecf20Sopenharmony_ci dev = &acard->wavefront; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci switch (cmd) { 16758c2ecf20Sopenharmony_ci case WFCTL_LOAD_SPP: 16768c2ecf20Sopenharmony_ci if (wavefront_load_patch (dev, argp) != 0) { 16778c2ecf20Sopenharmony_ci return -EIO; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci break; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci case WFCTL_WFCMD: 16828c2ecf20Sopenharmony_ci wc = memdup_user(argp, sizeof(*wc)); 16838c2ecf20Sopenharmony_ci if (IS_ERR(wc)) 16848c2ecf20Sopenharmony_ci return PTR_ERR(wc); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci if (wavefront_synth_control (acard, wc) < 0) 16878c2ecf20Sopenharmony_ci err = -EIO; 16888c2ecf20Sopenharmony_ci else if (copy_to_user (argp, wc, sizeof (*wc))) 16898c2ecf20Sopenharmony_ci err = -EFAULT; 16908c2ecf20Sopenharmony_ci else 16918c2ecf20Sopenharmony_ci err = 0; 16928c2ecf20Sopenharmony_ci kfree(wc); 16938c2ecf20Sopenharmony_ci return err; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci default: 16968c2ecf20Sopenharmony_ci return -EINVAL; 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci return 0; 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci/***********************************************************************/ 17048c2ecf20Sopenharmony_ci/* WaveFront: interface for card-level wavefront module */ 17058c2ecf20Sopenharmony_ci/***********************************************************************/ 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_civoid 17088c2ecf20Sopenharmony_cisnd_wavefront_internal_interrupt (snd_wavefront_card_t *card) 17098c2ecf20Sopenharmony_ci{ 17108c2ecf20Sopenharmony_ci snd_wavefront_t *dev = &card->wavefront; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci /* 17138c2ecf20Sopenharmony_ci Some comments on interrupts. I attempted a version of this 17148c2ecf20Sopenharmony_ci driver that used interrupts throughout the code instead of 17158c2ecf20Sopenharmony_ci doing busy and/or sleep-waiting. Alas, it appears that once 17168c2ecf20Sopenharmony_ci the Motorola firmware is downloaded, the card *never* 17178c2ecf20Sopenharmony_ci generates an RX interrupt. These are successfully generated 17188c2ecf20Sopenharmony_ci during firmware loading, and after that wavefront_status() 17198c2ecf20Sopenharmony_ci reports that an interrupt is pending on the card from time 17208c2ecf20Sopenharmony_ci to time, but it never seems to be delivered to this 17218c2ecf20Sopenharmony_ci driver. Note also that wavefront_status() continues to 17228c2ecf20Sopenharmony_ci report that RX interrupts are enabled, suggesting that I 17238c2ecf20Sopenharmony_ci didn't goof up and disable them by mistake. 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci Thus, I stepped back to a prior version of 17268c2ecf20Sopenharmony_ci wavefront_wait(), the only place where this really 17278c2ecf20Sopenharmony_ci matters. Its sad, but I've looked through the code to check 17288c2ecf20Sopenharmony_ci on things, and I really feel certain that the Motorola 17298c2ecf20Sopenharmony_ci firmware prevents RX-ready interrupts. 17308c2ecf20Sopenharmony_ci */ 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci if ((wavefront_status(dev) & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { 17338c2ecf20Sopenharmony_ci return; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci spin_lock(&dev->irq_lock); 17378c2ecf20Sopenharmony_ci dev->irq_ok = 1; 17388c2ecf20Sopenharmony_ci dev->irq_cnt++; 17398c2ecf20Sopenharmony_ci spin_unlock(&dev->irq_lock); 17408c2ecf20Sopenharmony_ci wake_up(&dev->interrupt_sleeper); 17418c2ecf20Sopenharmony_ci} 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci/* STATUS REGISTER 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci0 Host Rx Interrupt Enable (1=Enabled) 17468c2ecf20Sopenharmony_ci1 Host Rx Register Full (1=Full) 17478c2ecf20Sopenharmony_ci2 Host Rx Interrupt Pending (1=Interrupt) 17488c2ecf20Sopenharmony_ci3 Unused 17498c2ecf20Sopenharmony_ci4 Host Tx Interrupt (1=Enabled) 17508c2ecf20Sopenharmony_ci5 Host Tx Register empty (1=Empty) 17518c2ecf20Sopenharmony_ci6 Host Tx Interrupt Pending (1=Interrupt) 17528c2ecf20Sopenharmony_ci7 Unused 17538c2ecf20Sopenharmony_ci*/ 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_cistatic int 17568c2ecf20Sopenharmony_cisnd_wavefront_interrupt_bits (int irq) 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci int bits; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci switch (irq) { 17628c2ecf20Sopenharmony_ci case 9: 17638c2ecf20Sopenharmony_ci bits = 0x00; 17648c2ecf20Sopenharmony_ci break; 17658c2ecf20Sopenharmony_ci case 5: 17668c2ecf20Sopenharmony_ci bits = 0x08; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci case 12: 17698c2ecf20Sopenharmony_ci bits = 0x10; 17708c2ecf20Sopenharmony_ci break; 17718c2ecf20Sopenharmony_ci case 15: 17728c2ecf20Sopenharmony_ci bits = 0x18; 17738c2ecf20Sopenharmony_ci break; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci default: 17768c2ecf20Sopenharmony_ci snd_printk ("invalid IRQ %d\n", irq); 17778c2ecf20Sopenharmony_ci bits = -1; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci return bits; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_cistatic void 17848c2ecf20Sopenharmony_ciwavefront_should_cause_interrupt (snd_wavefront_t *dev, 17858c2ecf20Sopenharmony_ci int val, int port, unsigned long timeout) 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci wait_queue_entry_t wait; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci init_waitqueue_entry(&wait, current); 17918c2ecf20Sopenharmony_ci spin_lock_irq(&dev->irq_lock); 17928c2ecf20Sopenharmony_ci add_wait_queue(&dev->interrupt_sleeper, &wait); 17938c2ecf20Sopenharmony_ci dev->irq_ok = 0; 17948c2ecf20Sopenharmony_ci outb (val,port); 17958c2ecf20Sopenharmony_ci spin_unlock_irq(&dev->irq_lock); 17968c2ecf20Sopenharmony_ci while (!dev->irq_ok && time_before(jiffies, timeout)) { 17978c2ecf20Sopenharmony_ci schedule_timeout_uninterruptible(1); 17988c2ecf20Sopenharmony_ci barrier(); 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci} 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_cistatic int 18038c2ecf20Sopenharmony_ciwavefront_reset_to_cleanliness (snd_wavefront_t *dev) 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci{ 18068c2ecf20Sopenharmony_ci int bits; 18078c2ecf20Sopenharmony_ci int hwv[2]; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci /* IRQ already checked */ 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci bits = snd_wavefront_interrupt_bits (dev->irq); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci /* try reset of port */ 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci outb (0x0, dev->control_port); 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci /* At this point, the board is in reset, and the H/W initialization 18188c2ecf20Sopenharmony_ci register is accessed at the same address as the data port. 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_ci Bit 7 - Enable IRQ Driver 18218c2ecf20Sopenharmony_ci 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs 18228c2ecf20Sopenharmony_ci 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci Bit 6 - MIDI Interface Select 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci 0 - Use the MIDI Input from the 26-pin WaveBlaster 18278c2ecf20Sopenharmony_ci compatible header as the serial MIDI source 18288c2ecf20Sopenharmony_ci 1 - Use the MIDI Input from the 9-pin D connector as the 18298c2ecf20Sopenharmony_ci serial MIDI source. 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci Bits 5:3 - IRQ Selection 18328c2ecf20Sopenharmony_ci 0 0 0 - IRQ 2/9 18338c2ecf20Sopenharmony_ci 0 0 1 - IRQ 5 18348c2ecf20Sopenharmony_ci 0 1 0 - IRQ 12 18358c2ecf20Sopenharmony_ci 0 1 1 - IRQ 15 18368c2ecf20Sopenharmony_ci 1 0 0 - Reserved 18378c2ecf20Sopenharmony_ci 1 0 1 - Reserved 18388c2ecf20Sopenharmony_ci 1 1 0 - Reserved 18398c2ecf20Sopenharmony_ci 1 1 1 - Reserved 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci Bits 2:1 - Reserved 18428c2ecf20Sopenharmony_ci Bit 0 - Disable Boot ROM 18438c2ecf20Sopenharmony_ci 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM 18448c2ecf20Sopenharmony_ci 1 - memory accesses to 03FC30-03FFFFH are directed to external 18458c2ecf20Sopenharmony_ci storage. 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci */ 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci /* configure hardware: IRQ, enable interrupts, 18508c2ecf20Sopenharmony_ci plus external 9-pin MIDI interface selected 18518c2ecf20Sopenharmony_ci */ 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci outb (0x80 | 0x40 | bits, dev->data_port); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* CONTROL REGISTER 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci 0 Host Rx Interrupt Enable (1=Enabled) 0x1 18588c2ecf20Sopenharmony_ci 1 Unused 0x2 18598c2ecf20Sopenharmony_ci 2 Unused 0x4 18608c2ecf20Sopenharmony_ci 3 Unused 0x8 18618c2ecf20Sopenharmony_ci 4 Host Tx Interrupt Enable 0x10 18628c2ecf20Sopenharmony_ci 5 Mute (0=Mute; 1=Play) 0x20 18638c2ecf20Sopenharmony_ci 6 Master Interrupt Enable (1=Enabled) 0x40 18648c2ecf20Sopenharmony_ci 7 Master Reset (0=Reset; 1=Run) 0x80 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci Take us out of reset, mute output, master + TX + RX interrupts on. 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci We'll get an interrupt presumably to tell us that the TX 18698c2ecf20Sopenharmony_ci register is clear. 18708c2ecf20Sopenharmony_ci */ 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci wavefront_should_cause_interrupt(dev, 0x80|0x40|0x10|0x1, 18738c2ecf20Sopenharmony_ci dev->control_port, 18748c2ecf20Sopenharmony_ci (reset_time*HZ)/100); 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci /* Note: data port is now the data port, not the h/w initialization 18778c2ecf20Sopenharmony_ci port. 18788c2ecf20Sopenharmony_ci */ 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci if (!dev->irq_ok) { 18818c2ecf20Sopenharmony_ci snd_printk ("intr not received after h/w un-reset.\n"); 18828c2ecf20Sopenharmony_ci goto gone_bad; 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci /* Note: data port is now the data port, not the h/w initialization 18868c2ecf20Sopenharmony_ci port. 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci At this point, only "HW VERSION" or "DOWNLOAD OS" commands 18898c2ecf20Sopenharmony_ci will work. So, issue one of them, and wait for TX 18908c2ecf20Sopenharmony_ci interrupt. This can take a *long* time after a cold boot, 18918c2ecf20Sopenharmony_ci while the ISC ROM does its RAM test. The SDK says up to 4 18928c2ecf20Sopenharmony_ci seconds - with 12MB of RAM on a Tropez+, it takes a lot 18938c2ecf20Sopenharmony_ci longer than that (~16secs). Note that the card understands 18948c2ecf20Sopenharmony_ci the difference between a warm and a cold boot, so 18958c2ecf20Sopenharmony_ci subsequent ISC2115 reboots (say, caused by module 18968c2ecf20Sopenharmony_ci reloading) will get through this much faster. 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci XXX Interesting question: why is no RX interrupt received first ? 18998c2ecf20Sopenharmony_ci */ 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci wavefront_should_cause_interrupt(dev, WFC_HARDWARE_VERSION, 19028c2ecf20Sopenharmony_ci dev->data_port, ramcheck_time*HZ); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (!dev->irq_ok) { 19058c2ecf20Sopenharmony_ci snd_printk ("post-RAM-check interrupt not received.\n"); 19068c2ecf20Sopenharmony_ci goto gone_bad; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci if (!wavefront_wait (dev, STAT_CAN_READ)) { 19108c2ecf20Sopenharmony_ci snd_printk ("no response to HW version cmd.\n"); 19118c2ecf20Sopenharmony_ci goto gone_bad; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if ((hwv[0] = wavefront_read (dev)) == -1) { 19158c2ecf20Sopenharmony_ci snd_printk ("board not responding correctly.\n"); 19168c2ecf20Sopenharmony_ci goto gone_bad; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (hwv[0] == 0xFF) { /* NAK */ 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci /* Board's RAM test failed. Try to read error code, 19228c2ecf20Sopenharmony_ci and tell us about it either way. 19238c2ecf20Sopenharmony_ci */ 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if ((hwv[0] = wavefront_read (dev)) == -1) { 19268c2ecf20Sopenharmony_ci snd_printk ("on-board RAM test failed " 19278c2ecf20Sopenharmony_ci "(bad error code).\n"); 19288c2ecf20Sopenharmony_ci } else { 19298c2ecf20Sopenharmony_ci snd_printk ("on-board RAM test failed " 19308c2ecf20Sopenharmony_ci "(error code: 0x%x).\n", 19318c2ecf20Sopenharmony_ci hwv[0]); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci goto gone_bad; 19348c2ecf20Sopenharmony_ci } 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci /* We're OK, just get the next byte of the HW version response */ 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci if ((hwv[1] = wavefront_read (dev)) == -1) { 19398c2ecf20Sopenharmony_ci snd_printk ("incorrect h/w response.\n"); 19408c2ecf20Sopenharmony_ci goto gone_bad; 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci snd_printk ("hardware version %d.%d\n", 19448c2ecf20Sopenharmony_ci hwv[0], hwv[1]); 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci return 0; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci gone_bad: 19508c2ecf20Sopenharmony_ci return (1); 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_cistatic int 19548c2ecf20Sopenharmony_ciwavefront_download_firmware (snd_wavefront_t *dev, char *path) 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci const unsigned char *buf; 19588c2ecf20Sopenharmony_ci int len, err; 19598c2ecf20Sopenharmony_ci int section_cnt_downloaded = 0; 19608c2ecf20Sopenharmony_ci const struct firmware *firmware; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci err = request_firmware(&firmware, path, dev->card->dev); 19638c2ecf20Sopenharmony_ci if (err < 0) { 19648c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "firmware (%s) download failed!!!\n", path); 19658c2ecf20Sopenharmony_ci return 1; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci len = 0; 19698c2ecf20Sopenharmony_ci buf = firmware->data; 19708c2ecf20Sopenharmony_ci for (;;) { 19718c2ecf20Sopenharmony_ci int section_length = *(signed char *)buf; 19728c2ecf20Sopenharmony_ci if (section_length == 0) 19738c2ecf20Sopenharmony_ci break; 19748c2ecf20Sopenharmony_ci if (section_length < 0 || section_length > WF_SECTION_MAX) { 19758c2ecf20Sopenharmony_ci snd_printk(KERN_ERR 19768c2ecf20Sopenharmony_ci "invalid firmware section length %d\n", 19778c2ecf20Sopenharmony_ci section_length); 19788c2ecf20Sopenharmony_ci goto failure; 19798c2ecf20Sopenharmony_ci } 19808c2ecf20Sopenharmony_ci buf++; 19818c2ecf20Sopenharmony_ci len++; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci if (firmware->size < len + section_length) { 19848c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "firmware section read error.\n"); 19858c2ecf20Sopenharmony_ci goto failure; 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* Send command */ 19898c2ecf20Sopenharmony_ci if (wavefront_write(dev, WFC_DOWNLOAD_OS)) 19908c2ecf20Sopenharmony_ci goto failure; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci for (; section_length; section_length--) { 19938c2ecf20Sopenharmony_ci if (wavefront_write(dev, *buf)) 19948c2ecf20Sopenharmony_ci goto failure; 19958c2ecf20Sopenharmony_ci buf++; 19968c2ecf20Sopenharmony_ci len++; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* get ACK */ 20008c2ecf20Sopenharmony_ci if (!wavefront_wait(dev, STAT_CAN_READ)) { 20018c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "time out for firmware ACK.\n"); 20028c2ecf20Sopenharmony_ci goto failure; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci err = inb(dev->data_port); 20058c2ecf20Sopenharmony_ci if (err != WF_ACK) { 20068c2ecf20Sopenharmony_ci snd_printk(KERN_ERR 20078c2ecf20Sopenharmony_ci "download of section #%d not " 20088c2ecf20Sopenharmony_ci "acknowledged, ack = 0x%x\n", 20098c2ecf20Sopenharmony_ci section_cnt_downloaded + 1, err); 20108c2ecf20Sopenharmony_ci goto failure; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci section_cnt_downloaded++; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci release_firmware(firmware); 20178c2ecf20Sopenharmony_ci return 0; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci failure: 20208c2ecf20Sopenharmony_ci release_firmware(firmware); 20218c2ecf20Sopenharmony_ci snd_printk(KERN_ERR "firmware download failed!!!\n"); 20228c2ecf20Sopenharmony_ci return 1; 20238c2ecf20Sopenharmony_ci} 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_cistatic int 20278c2ecf20Sopenharmony_ciwavefront_do_reset (snd_wavefront_t *dev) 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci{ 20308c2ecf20Sopenharmony_ci char voices[1]; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (wavefront_reset_to_cleanliness (dev)) { 20338c2ecf20Sopenharmony_ci snd_printk ("hw reset failed.\n"); 20348c2ecf20Sopenharmony_ci goto gone_bad; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (dev->israw) { 20388c2ecf20Sopenharmony_ci if (wavefront_download_firmware (dev, ospath)) { 20398c2ecf20Sopenharmony_ci goto gone_bad; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci dev->israw = 0; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci /* Wait for the OS to get running. The protocol for 20458c2ecf20Sopenharmony_ci this is non-obvious, and was determined by 20468c2ecf20Sopenharmony_ci using port-IO tracing in DOSemu and some 20478c2ecf20Sopenharmony_ci experimentation here. 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci Rather than using timed waits, use interrupts creatively. 20508c2ecf20Sopenharmony_ci */ 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci wavefront_should_cause_interrupt (dev, WFC_NOOP, 20538c2ecf20Sopenharmony_ci dev->data_port, 20548c2ecf20Sopenharmony_ci (osrun_time*HZ)); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci if (!dev->irq_ok) { 20578c2ecf20Sopenharmony_ci snd_printk ("no post-OS interrupt.\n"); 20588c2ecf20Sopenharmony_ci goto gone_bad; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci /* Now, do it again ! */ 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci wavefront_should_cause_interrupt (dev, WFC_NOOP, 20648c2ecf20Sopenharmony_ci dev->data_port, (10*HZ)); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci if (!dev->irq_ok) { 20678c2ecf20Sopenharmony_ci snd_printk ("no post-OS interrupt(2).\n"); 20688c2ecf20Sopenharmony_ci goto gone_bad; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci /* OK, no (RX/TX) interrupts any more, but leave mute 20728c2ecf20Sopenharmony_ci in effect. 20738c2ecf20Sopenharmony_ci */ 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci outb (0x80|0x40, dev->control_port); 20768c2ecf20Sopenharmony_ci } 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci /* SETUPSND.EXE asks for sample memory config here, but since i 20798c2ecf20Sopenharmony_ci have no idea how to interpret the result, we'll forget 20808c2ecf20Sopenharmony_ci about it. 20818c2ecf20Sopenharmony_ci */ 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci if ((dev->freemem = wavefront_freemem (dev)) < 0) { 20848c2ecf20Sopenharmony_ci goto gone_bad; 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci snd_printk ("available DRAM %dk\n", dev->freemem / 1024); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (wavefront_write (dev, 0xf0) || 20908c2ecf20Sopenharmony_ci wavefront_write (dev, 1) || 20918c2ecf20Sopenharmony_ci (wavefront_read (dev) < 0)) { 20928c2ecf20Sopenharmony_ci dev->debug = 0; 20938c2ecf20Sopenharmony_ci snd_printk ("MPU emulation mode not set.\n"); 20948c2ecf20Sopenharmony_ci goto gone_bad; 20958c2ecf20Sopenharmony_ci } 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci voices[0] = 32; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_SET_NVOICES, NULL, voices)) { 21008c2ecf20Sopenharmony_ci snd_printk ("cannot set number of voices to 32.\n"); 21018c2ecf20Sopenharmony_ci goto gone_bad; 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci return 0; 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci gone_bad: 21088c2ecf20Sopenharmony_ci /* reset that sucker so that it doesn't bother us. */ 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci outb (0x0, dev->control_port); 21118c2ecf20Sopenharmony_ci dev->interrupts_are_midi = 0; 21128c2ecf20Sopenharmony_ci return 1; 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ciint 21168c2ecf20Sopenharmony_cisnd_wavefront_start (snd_wavefront_t *dev) 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci{ 21198c2ecf20Sopenharmony_ci int samples_are_from_rom; 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci /* IMPORTANT: assumes that snd_wavefront_detect() and/or 21228c2ecf20Sopenharmony_ci wavefront_reset_to_cleanliness() has already been called 21238c2ecf20Sopenharmony_ci */ 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci if (dev->israw) { 21268c2ecf20Sopenharmony_ci samples_are_from_rom = 1; 21278c2ecf20Sopenharmony_ci } else { 21288c2ecf20Sopenharmony_ci /* XXX is this always true ? */ 21298c2ecf20Sopenharmony_ci samples_are_from_rom = 0; 21308c2ecf20Sopenharmony_ci } 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci if (dev->israw || fx_raw) { 21338c2ecf20Sopenharmony_ci if (wavefront_do_reset (dev)) { 21348c2ecf20Sopenharmony_ci return -1; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci } 21378c2ecf20Sopenharmony_ci /* Check for FX device, present only on Tropez+ */ 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci dev->has_fx = (snd_wavefront_fx_detect (dev) == 0); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci if (dev->has_fx && fx_raw) { 21428c2ecf20Sopenharmony_ci snd_wavefront_fx_start (dev); 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci wavefront_get_sample_status (dev, samples_are_from_rom); 21468c2ecf20Sopenharmony_ci wavefront_get_program_status (dev); 21478c2ecf20Sopenharmony_ci wavefront_get_patch_status (dev); 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci /* Start normal operation: unreset, master interrupt enabled, no mute 21508c2ecf20Sopenharmony_ci */ 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci outb (0x80|0x40|0x20, dev->control_port); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci return (0); 21558c2ecf20Sopenharmony_ci} 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ciint 21588c2ecf20Sopenharmony_cisnd_wavefront_detect (snd_wavefront_card_t *card) 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci{ 21618c2ecf20Sopenharmony_ci unsigned char rbuf[4], wbuf[4]; 21628c2ecf20Sopenharmony_ci snd_wavefront_t *dev = &card->wavefront; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci /* returns zero if a WaveFront card is successfully detected. 21658c2ecf20Sopenharmony_ci negative otherwise. 21668c2ecf20Sopenharmony_ci */ 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci dev->israw = 0; 21698c2ecf20Sopenharmony_ci dev->has_fx = 0; 21708c2ecf20Sopenharmony_ci dev->debug = debug_default; 21718c2ecf20Sopenharmony_ci dev->interrupts_are_midi = 0; 21728c2ecf20Sopenharmony_ci dev->irq_cnt = 0; 21738c2ecf20Sopenharmony_ci dev->rom_samples_rdonly = 1; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci dev->fw_version[0] = rbuf[0]; 21788c2ecf20Sopenharmony_ci dev->fw_version[1] = rbuf[1]; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci snd_printk ("firmware %d.%d already loaded.\n", 21818c2ecf20Sopenharmony_ci rbuf[0], rbuf[1]); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci /* check that a command actually works */ 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci if (snd_wavefront_cmd (dev, WFC_HARDWARE_VERSION, 21868c2ecf20Sopenharmony_ci rbuf, wbuf) == 0) { 21878c2ecf20Sopenharmony_ci dev->hw_version[0] = rbuf[0]; 21888c2ecf20Sopenharmony_ci dev->hw_version[1] = rbuf[1]; 21898c2ecf20Sopenharmony_ci } else { 21908c2ecf20Sopenharmony_ci snd_printk ("not raw, but no " 21918c2ecf20Sopenharmony_ci "hardware version!\n"); 21928c2ecf20Sopenharmony_ci return -1; 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci if (!wf_raw) { 21968c2ecf20Sopenharmony_ci return 0; 21978c2ecf20Sopenharmony_ci } else { 21988c2ecf20Sopenharmony_ci snd_printk ("reloading firmware as you requested.\n"); 21998c2ecf20Sopenharmony_ci dev->israw = 1; 22008c2ecf20Sopenharmony_ci } 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci } else { 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci dev->israw = 1; 22058c2ecf20Sopenharmony_ci snd_printk ("no response to firmware probe, assume raw.\n"); 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci return 0; 22108c2ecf20Sopenharmony_ci} 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ciMODULE_FIRMWARE(DEFAULT_OSPATH); 2213