⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wavfront.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  -*- linux-c -*- * * sound/wavfront.c * * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus) * * This driver supports the onboard wavetable synthesizer (an ICS2115), * including patch, sample and program loading and unloading, conversion * of GUS patches during loading, and full user-level access to all * WaveFront commands. It tries to provide semi-intelligent patch and * sample management as well. * * It also provides support for the ICS emulation of an MPU-401.  Full * support for the ICS emulation's "virtual MIDI mode" is provided in * wf_midi.c. * * Support is also provided for the Tropez Plus' onboard FX processor, * a Yamaha YSS225. Currently, code exists to configure the YSS225, * and there is an interface allowing tweaking of any of its memory * addresses. However, I have been unable to decipher the logical * positioning of the configuration info for various effects, so for * now, you just get the YSS225 in the same state as Turtle Beach's * "SETUPSND.EXE" utility leaves it. * * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co], * This chip also controls the configuration of the card: the wavefront * synth is logical unit 4. * * * Supported devices: * *   /dev/dsp                      - using cs4232+ad1848 modules, OSS compatible *   /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible *   /dev/synth00                  - raw synth interface *  ********************************************************************** * * Copyright (C) by Paul Barton-Davis 1998 * * Some portions of this file are taken from work that is * copyright (C) by Hannu Savolainen 1993-1996 * * Although the relevant code here is all new, the handling of * sample/alias/multi- samples is entirely based on a driver by Matt * Martin and Rutger Nijlunsing which demonstrated how to get things * to work correctly. The GUS patch loading code has been almost * unaltered by me, except to fit formatting and function names in the * rest of the file. Many thanks to them. * * Appreciation and thanks to Hannu Savolainen for his early work on the Maui * driver, and answering a few questions while this one was developed. * * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their * complete lack of help in developing this driver, and in particular * for their utter silence in response to questions about undocumented * aspects of configuring a WaveFront soundcard, particularly the * effects processor. * * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $ * * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. * * Changes: * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org> *		Added some __init and __initdata to entries in yss225.c */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/ptrace.h>#include <linux/fcntl.h>#include <linux/ioport.h>    #include <linux/interrupt.h>#include <linux/config.h>#include <linux/delay.h>#include "sound_config.h"#include <linux/wavefront.h>/* *	This sucks, hopefully it'll get standardised */ #if defined(__alpha__)#ifdef CONFIG_SMP#define LOOPS_PER_TICK cpu_data[smp_processor_id()].loops_per_jiffy#else#define LOOPS_PER_TICK	loops_per_sec#endif#endif#if defined(__i386__)#define LOOPS_PER_TICK current_cpu_data.loops_per_jiffy#endif #define _MIDI_SYNTH_C_#define MIDI_SYNTH_NAME	"WaveFront MIDI"#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT#include "midi_synth.h"/* Compile-time control of the extent to which OSS is supported.   I consider /dev/sequencer to be an anachronism, but given its   widespread usage by various Linux MIDI software, it seems worth   offering support to it if its not too painful. Instead of using   /dev/sequencer, I recommend:     for synth programming and patch loading: /dev/synthNN     for kernel-synchronized MIDI sequencing: the ALSA sequencer     for direct MIDI control: /dev/midiNN   I have never tried static compilation into the kernel. The #if's   for this are really just notes to myself about what the code is   for.*/#define OSS_SUPPORT_SEQ            0x1  /* use of /dev/sequencer */#define OSS_SUPPORT_STATIC_INSTALL 0x2  /* static compilation into kernel */#define OSS_SUPPORT_LEVEL          0x1  /* just /dev/sequencer for now */#if    OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQstatic int (*midi_load_patch) (int devno, int format, const char *addr,			       int offs, int count, int pmgr_flag) = NULL;#endif OSS_SUPPORT_SEQ/* if WF_DEBUG not defined, no run-time debugging messages will   be available via the debug flag setting. Given the current   beta state of the driver, this will remain set until a future    version.*/#define WF_DEBUG 1#ifdef WF_DEBUG/* Thank goodness for gcc's preprocessor ... */#define DPRINT(cond, format, args...) \       if ((dev.debug & (cond)) == (cond)) { \	     printk (KERN_DEBUG LOGNAME format, ## args); \       }#else#define DPRINT(cond, format, args...)#endif#define LOGNAME "WaveFront: "/* bitmasks for WaveFront status port value */#define STAT_RINTR_ENABLED	0x01#define STAT_CAN_READ		0x02#define STAT_INTR_READ		0x04#define STAT_WINTR_ENABLED	0x10#define STAT_CAN_WRITE		0x20#define STAT_INTR_WRITE		0x40/*** Module-accessible parameters ***************************************/int wf_raw = 0; /* we normally check for "raw state" to firmware		   loading. if set, then during driver loading, the		   state of the board is ignored, and we reset the		   board and load the firmware anyway.		*/		   int fx_raw = 1; /* if this is zero, we'll leave the FX processor in		   whatever state it is when the driver is loaded.		   The default is to download the microprogram and		   associated coefficients to set it up for "default"		   operation, whatever that means.		*/int debug_default = 0;  /* you can set this to control debugging			      during driver loading. it takes any combination			      of the WF_DEBUG_* flags defined in			      wavefront.h			   *//* XXX this needs to be made firmware and hardware version dependent */char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed					     version of the WaveFront OS					  */int wait_usecs = 150; /* This magic number seems to give pretty optimal			 throughput based on my limited experimentation.			 If you want to play around with it and find a better			 value, be my guest. Remember, the idea is to			 get a number that causes us to just busy wait			 for as many WaveFront commands as possible, without			 coming up with a number so large that we hog the			 whole CPU.			 Specifically, with this number, out of about 134,000			 status waits, only about 250 result in a sleep.		      */int sleep_interval = 100;     /* HZ/sleep_interval seconds per sleep */int sleep_tries = 50;       /* number of times we'll try to sleep */int reset_time = 2;        /* hundreths of a second we wait after a HW reset for			      the expected interrupt.			   */int ramcheck_time = 20;    /* time in seconds to wait while ROM code			      checks on-board RAM.			   */int osrun_time = 10;       /* time in seconds we wait for the OS to			      start running.			   */MODULE_PARM(wf_raw,"i");MODULE_PARM(fx_raw,"i");MODULE_PARM(debug_default,"i");MODULE_PARM(wait_usecs,"i");MODULE_PARM(sleep_interval,"i");MODULE_PARM(sleep_tries,"i");MODULE_PARM(ospath,"s");MODULE_PARM(reset_time,"i");MODULE_PARM(ramcheck_time,"i");MODULE_PARM(osrun_time,"i");/***************************************************************************//* Note: because this module doesn't export any symbols, this really isn't   a global variable, even if it looks like one. I was quite confused by   this when I started writing this as a (newer) module -- pbd.*/struct wf_config {	int devno;            /* device number from kernel */	int irq;              /* "you were one, one of the few ..." */	int base;             /* low i/o port address */#define mpu_data_port    base #define mpu_command_port base + 1 /* write semantics */#define mpu_status_port  base + 1 /* read semantics */#define data_port        base + 2 #define status_port      base + 3 /* read semantics */#define control_port     base + 3 /* write semantics  */#define block_port       base + 4 /* 16 bit, writeonly */#define last_block_port  base + 6 /* 16 bit, writeonly */	/* FX ports. These are mapped through the ICS2115 to the YS225.	   The ICS2115 takes care of flipping the relevant pins on the	   YS225 so that access to each of these ports does the right	   thing. Note: these are NOT documented by Turtle Beach.	*/#define fx_status       base + 8 #define fx_op           base + 8 #define fx_lcr          base + 9 #define fx_dsp_addr     base + 0xa#define fx_dsp_page     base + 0xb #define fx_dsp_lsb      base + 0xc #define fx_dsp_msb      base + 0xd #define fx_mod_addr     base + 0xe#define fx_mod_data     base + 0xf 	volatile int irq_ok;               /* set by interrupt handler */        volatile int irq_cnt;              /* ditto */	int opened;                        /* flag, holds open(2) mode */	char debug;                        /* debugging flags */	int freemem;                       /* installed RAM, in bytes */ 	int synth_dev;                     /* devno for "raw" synth */	int mididev;                       /* devno for internal MIDI */	int ext_mididev;                   /* devno for external MIDI */         int fx_mididev;                    /* devno for FX MIDI interface */#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ	int oss_dev;                      /* devno for OSS sequencer synth */#endif OSS_SUPPORT_SEQ	char fw_version[2];                /* major = [0], minor = [1] */	char hw_version[2];                /* major = [0], minor = [1] */	char israw;                        /* needs Motorola microcode */	char has_fx;                       /* has FX processor (Tropez+) */	char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */	char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */	char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */	int samples_used;                  /* how many */	char interrupts_on;                /* h/w MPU interrupts enabled ? */	char rom_samples_rdonly;           /* can we write on ROM samples */	wait_queue_head_t interrupt_sleeper; } dev;static int  detect_wffx(void);static int  wffx_ioctl (wavefront_fx_info *);static int  wffx_init (void);static int wavefront_delete_sample (int sampnum);static int wavefront_find_free_sample (void);/* From wf_midi.c */extern int  virtual_midi_enable  (void);extern int  virtual_midi_disable (void);extern int  detect_wf_mpu (int, int);extern int  install_wf_mpu (void);extern int  uninstall_wf_mpu (void);typedef struct {	int cmd;	char *action;	unsigned int read_cnt;	unsigned int write_cnt;	int need_ack;} wavefront_command;static struct {	int errno;	const char *errstr;} wavefront_errors[] = {	{ 0x01, "Bad sample number" },	{ 0x02, "Out of sample memory" },	{ 0x03, "Bad patch number" },	{ 0x04, "Error in number of voices" },	{ 0x06, "Sample load already in progress" },	{ 0x0B, "No sample load request pending" },	{ 0x0E, "Bad MIDI channel number" },	{ 0x10, "Download Record Error" },	{ 0x80, "Success" },	{ 0x0, 0x0 }};#define NEEDS_ACK 1static wavefront_command wavefront_commands[] = {	{ WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK },	{ WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0},	{ WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK },	{ WFC_GET_NVOICES, "get number of voices", 1, 0, 0 },	{ WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK },	{ WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 },	{ WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK },	{ WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK },	{ WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 },	{ WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK },	{ WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK },	{ WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK },	{ WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK },	{ WFC_MIDI_STATUS, "report midi status", 1, 0, 0 },	{ WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 },	{ WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 },	{ WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 },	{ WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 },	{ WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 },	{ WFC_DOWNLOAD_SAMPLE, "download sample",	  0, WF_SAMPLE_BYTES, NEEDS_ACK },	{ WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK},	{ WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header",	  0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK },	{ WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 },	/* This command requires a variable number of bytes to be written.	   There is a hack in wavefront_cmd() to support this. The actual	   count is passed in as the read buffer ptr, cast appropriately.	   Ugh.	*/	{ WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK },	/* This one is a hack as well. We just read the first byte of the	   response, don't fetch an ACK, and leave the rest to the 	   calling function. Ugly, ugly, ugly.	*/	{ WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 },	{ WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias",	  0, WF_ALIAS_BYTES, NEEDS_ACK },	{ WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0},	{ WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK },	{ WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 },	{ WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" },	{ WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 },	{ WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK },	{ WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 },	{ WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK },	{ WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 },	{ WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9,	  NEEDS_ACK},	{ WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0},	{ WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel",	  0, 1, NEEDS_ACK },	{ WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK },	{ WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers",	  32, 0, 0 },	{ WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK },	{ 0x00 }};static const char *wavefront_errorstr (int errnum){	int i;	for (i = 0; wavefront_errors[i].errstr; i++) {		if (wavefront_errors[i].errno == errnum) {			return wavefront_errors[i].errstr;		}	}	return "Unknown WaveFront error";}static wavefront_command *wavefront_get_command (int cmd) {	int i;	for (i = 0; wavefront_commands[i].cmd != 0; i++) {		if (cmd == wavefront_commands[i].cmd) {			return &wavefront_commands[i];		}	}	return (wavefront_command *) 0;}static inline intwavefront_status (void) {	return inb (dev.status_port);}static intwavefront_sleep (int limit){	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(limit);	return signal_pending(current);}static intwavefront_wait (int mask){	int             i;	static int      short_loop_cnt = 0;	/* Compute the loop count that lets us sleep for about the	   right amount of time, cache issues, bus speeds and all	   other issues being unequal but largely irrelevant.	*/	if (short_loop_cnt == 0) {		short_loop_cnt = wait_usecs *			(LOOPS_PER_TICK / (1000000 / HZ));	}	/* Spin for a short period of time, because >99% of all	   requests to the WaveFront can be serviced inline like this.	*/	for (i = 0; i < short_loop_cnt; i++) {		if (wavefront_status() & mask) {			return 1;		}	}	for (i = 0; i < sleep_tries; i++) {		if (wavefront_status() & mask) {			return 1;		}		if (wavefront_sleep (HZ/sleep_interval)) {			return (0);		}	}	return (0);}static intwavefront_read (void){	if (wavefront_wait (STAT_CAN_READ))		return inb (dev.data_port);	DPRINT (WF_DEBUG_DATA, "read timeout.\n");	return -1;}static intwavefront_write (unsigned char data){	if (wavefront_wait (STAT_CAN_WRITE)) {		outb (data, dev.data_port);		return 0;	}	DPRINT (WF_DEBUG_DATA, "write timeout.\n");	return -1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -