brintos

brintos / linux-shallow public Read only

0
0
Text · 12.3 KiB · ac5da12 Raw
399 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>4 */5 6#include <linux/delay.h>7#include <linux/interrupt.h>8#include <linux/time.h>9#include <sound/core.h>10#include <sound/gus.h>11 12extern int snd_gf1_synth_init(struct snd_gus_card * gus);13extern void snd_gf1_synth_done(struct snd_gus_card * gus);14 15/*16 *  ok.. default interrupt handlers...17 */18 19static void snd_gf1_default_interrupt_handler_midi_out(struct snd_gus_card * gus)20{21	snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd &= ~0x20);22}23 24static void snd_gf1_default_interrupt_handler_midi_in(struct snd_gus_card * gus)25{26	snd_gf1_uart_cmd(gus, gus->gf1.uart_cmd &= ~0x80);27}28 29static void snd_gf1_default_interrupt_handler_timer1(struct snd_gus_card * gus)30{31	snd_gf1_i_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, gus->gf1.timer_enabled &= ~4);32}33 34static void snd_gf1_default_interrupt_handler_timer2(struct snd_gus_card * gus)35{36	snd_gf1_i_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, gus->gf1.timer_enabled &= ~8);37}38 39static void snd_gf1_default_interrupt_handler_wave_and_volume(struct snd_gus_card * gus, struct snd_gus_voice * voice)40{41	snd_gf1_i_ctrl_stop(gus, 0x00);42	snd_gf1_i_ctrl_stop(gus, 0x0d);43}44 45static void snd_gf1_default_interrupt_handler_dma_write(struct snd_gus_card * gus)46{47	snd_gf1_i_write8(gus, 0x41, 0x00);48}49 50static void snd_gf1_default_interrupt_handler_dma_read(struct snd_gus_card * gus)51{52	snd_gf1_i_write8(gus, 0x49, 0x00);53}54 55void snd_gf1_set_default_handlers(struct snd_gus_card * gus, unsigned int what)56{57	if (what & SNDRV_GF1_HANDLER_MIDI_OUT)58		gus->gf1.interrupt_handler_midi_out = snd_gf1_default_interrupt_handler_midi_out;59	if (what & SNDRV_GF1_HANDLER_MIDI_IN)60		gus->gf1.interrupt_handler_midi_in = snd_gf1_default_interrupt_handler_midi_in;61	if (what & SNDRV_GF1_HANDLER_TIMER1)62		gus->gf1.interrupt_handler_timer1 = snd_gf1_default_interrupt_handler_timer1;63	if (what & SNDRV_GF1_HANDLER_TIMER2)64		gus->gf1.interrupt_handler_timer2 = snd_gf1_default_interrupt_handler_timer2;65	if (what & SNDRV_GF1_HANDLER_VOICE) {66		struct snd_gus_voice *voice;67		68		voice = &gus->gf1.voices[what & 0xffff];69		voice->handler_wave =70		voice->handler_volume = snd_gf1_default_interrupt_handler_wave_and_volume;71		voice->handler_effect = NULL;72		voice->volume_change = NULL;73	}74	if (what & SNDRV_GF1_HANDLER_DMA_WRITE)75		gus->gf1.interrupt_handler_dma_write = snd_gf1_default_interrupt_handler_dma_write;76	if (what & SNDRV_GF1_HANDLER_DMA_READ)77		gus->gf1.interrupt_handler_dma_read = snd_gf1_default_interrupt_handler_dma_read;78}79 80/*81 82 */83 84static void snd_gf1_clear_regs(struct snd_gus_card * gus)85{86	unsigned long flags;87 88	spin_lock_irqsave(&gus->reg_lock, flags);89	inb(GUSP(gus, IRQSTAT));90	snd_gf1_write8(gus, 0x41, 0);	/* DRAM DMA Control Register */91	snd_gf1_write8(gus, 0x45, 0);	/* Timer Control */92	snd_gf1_write8(gus, 0x49, 0);	/* Sampling Control Register */93	spin_unlock_irqrestore(&gus->reg_lock, flags);94}95 96static void snd_gf1_look_regs(struct snd_gus_card * gus)97{98	unsigned long flags;99 100	spin_lock_irqsave(&gus->reg_lock, flags);101	snd_gf1_look8(gus, 0x41);	/* DRAM DMA Control Register */102	snd_gf1_look8(gus, 0x49);	/* Sampling Control Register */103	inb(GUSP(gus, IRQSTAT));104	snd_gf1_read8(gus, 0x0f);	/* IRQ Source Register */105	spin_unlock_irqrestore(&gus->reg_lock, flags);106}107 108/*109 *  put selected GF1 voices to initial stage...110 */111 112void snd_gf1_smart_stop_voice(struct snd_gus_card * gus, unsigned short voice)113{114	unsigned long flags;115 116	spin_lock_irqsave(&gus->reg_lock, flags);117	snd_gf1_select_voice(gus, voice);118#if 0119	dev_dbg(gus->card->dev,120		" -%i- smart stop voice - volume = 0x%x\n",121		voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));122#endif123	snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);124	snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);125	spin_unlock_irqrestore(&gus->reg_lock, flags);126}127 128void snd_gf1_stop_voice(struct snd_gus_card * gus, unsigned short voice)129{130	unsigned long flags;131 132	spin_lock_irqsave(&gus->reg_lock, flags);133	snd_gf1_select_voice(gus, voice);134#if 0135	dev_dbg(gus->card->dev,136		" -%i- stop voice - volume = 0x%x\n",137		voice, snd_gf1_i_read16(gus, SNDRV_GF1_VW_VOLUME));138#endif139	snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);140	snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);141	if (gus->gf1.enh_mode)142		snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0);143	spin_unlock_irqrestore(&gus->reg_lock, flags);144#if 0145	snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_VIBRATO);146	snd_gf1_lfo_shutdown(gus, voice, ULTRA_LFO_TREMOLO);147#endif148}149 150static void snd_gf1_clear_voices(struct snd_gus_card * gus, unsigned short v_min,151				 unsigned short v_max)152{153	unsigned long flags;154	unsigned int daddr;155	unsigned short i, w_16;156 157	daddr = gus->gf1.default_voice_address << 4;158	for (i = v_min; i <= v_max; i++) {159#if 0160		if (gus->gf1.syn_voices)161			gus->gf1.syn_voices[i].flags = ~VFLG_DYNAMIC;162#endif163		spin_lock_irqsave(&gus->reg_lock, flags);164		snd_gf1_select_voice(gus, i);165		snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_ADDRESS_CONTROL);	/* Voice Control Register = voice stop */166		snd_gf1_ctrl_stop(gus, SNDRV_GF1_VB_VOLUME_CONTROL);	/* Volume Ramp Control Register = ramp off */167		if (gus->gf1.enh_mode)168			snd_gf1_write8(gus, SNDRV_GF1_VB_MODE, gus->gf1.memory ? 0x02 : 0x82);	/* Deactivate voice */169		w_16 = snd_gf1_read8(gus, SNDRV_GF1_VB_ADDRESS_CONTROL) & 0x04;170		snd_gf1_write16(gus, SNDRV_GF1_VW_FREQUENCY, 0x400);171		snd_gf1_write_addr(gus, SNDRV_GF1_VA_START, daddr, w_16);172		snd_gf1_write_addr(gus, SNDRV_GF1_VA_END, daddr, w_16);173		snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, 0);174		snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, 0);175		snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 0);176		snd_gf1_write16(gus, SNDRV_GF1_VW_VOLUME, 0);177		snd_gf1_write_addr(gus, SNDRV_GF1_VA_CURRENT, daddr, w_16);178		snd_gf1_write8(gus, SNDRV_GF1_VB_PAN, 7);179		if (gus->gf1.enh_mode) {180			snd_gf1_write8(gus, SNDRV_GF1_VB_ACCUMULATOR, 0);181			snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME, 0);182			snd_gf1_write16(gus, SNDRV_GF1_VW_EFFECT_VOLUME_FINAL, 0);183		}184		spin_unlock_irqrestore(&gus->reg_lock, flags);185#if 0186		snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_VIBRATO);187		snd_gf1_lfo_shutdown(gus, i, ULTRA_LFO_TREMOLO);188#endif189	}190}191 192void snd_gf1_stop_voices(struct snd_gus_card * gus, unsigned short v_min, unsigned short v_max)193{194	unsigned long flags;195	short i, ramp_ok;196	unsigned short ramp_end;197 198	if (!in_interrupt()) {	/* this can't be done in interrupt */199		for (i = v_min, ramp_ok = 0; i <= v_max; i++) {200			spin_lock_irqsave(&gus->reg_lock, flags);201			snd_gf1_select_voice(gus, i);202			ramp_end = snd_gf1_read16(gus, 9) >> 8;203			if (ramp_end > SNDRV_GF1_MIN_OFFSET) {204				ramp_ok++;205				snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_RATE, 20);	/* ramp rate */206				snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_START, SNDRV_GF1_MIN_OFFSET);	/* ramp start */207				snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_END, ramp_end);	/* ramp end */208				snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, 0x40);	/* ramp down */209				if (gus->gf1.enh_mode) {210					snd_gf1_delay(gus);211					snd_gf1_write8(gus, SNDRV_GF1_VB_VOLUME_CONTROL, 0x40);212				}213			}214			spin_unlock_irqrestore(&gus->reg_lock, flags);215		}216		msleep_interruptible(50);217	}218	snd_gf1_clear_voices(gus, v_min, v_max);219}220 221static void snd_gf1_alloc_voice_use(struct snd_gus_card * gus, 222				    struct snd_gus_voice * pvoice,223				    int type, int client, int port)224{225	pvoice->use = 1;226	switch (type) {227	case SNDRV_GF1_VOICE_TYPE_PCM:228		gus->gf1.pcm_alloc_voices++;229		pvoice->pcm = 1;230		break;231	case SNDRV_GF1_VOICE_TYPE_SYNTH:232		pvoice->synth = 1;233		pvoice->client = client;234		pvoice->port = port;235		break;236	case SNDRV_GF1_VOICE_TYPE_MIDI:237		pvoice->midi = 1;238		pvoice->client = client;239		pvoice->port = port;240		break;241	}242}243 244struct snd_gus_voice *snd_gf1_alloc_voice(struct snd_gus_card * gus, int type, int client, int port)245{246	struct snd_gus_voice *pvoice;247	unsigned long flags;248	int idx;249 250	spin_lock_irqsave(&gus->voice_alloc, flags);251	if (type == SNDRV_GF1_VOICE_TYPE_PCM) {252		if (gus->gf1.pcm_alloc_voices >= gus->gf1.pcm_channels) {253			spin_unlock_irqrestore(&gus->voice_alloc, flags);254			return NULL;255		}256	}257	for (idx = 0; idx < 32; idx++) {258		pvoice = &gus->gf1.voices[idx];259		if (!pvoice->use) {260			snd_gf1_alloc_voice_use(gus, pvoice, type, client, port);261			spin_unlock_irqrestore(&gus->voice_alloc, flags);262			return pvoice;263		}264	} 265	for (idx = 0; idx < 32; idx++) {266		pvoice = &gus->gf1.voices[idx];267		if (pvoice->midi && !pvoice->client) {268			snd_gf1_clear_voices(gus, pvoice->number, pvoice->number);269			snd_gf1_alloc_voice_use(gus, pvoice, type, client, port);270			spin_unlock_irqrestore(&gus->voice_alloc, flags);271			return pvoice;272		}273	} 274	spin_unlock_irqrestore(&gus->voice_alloc, flags);275	return NULL;276}277 278void snd_gf1_free_voice(struct snd_gus_card * gus, struct snd_gus_voice *voice)279{280	unsigned long flags;281	void (*private_free)(struct snd_gus_voice *voice);282 283	if (voice == NULL || !voice->use)284		return;285	snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_VOICE | voice->number);286	snd_gf1_clear_voices(gus, voice->number, voice->number);287	spin_lock_irqsave(&gus->voice_alloc, flags);288	private_free = voice->private_free;289	voice->private_free = NULL;290	voice->private_data = NULL;291	if (voice->pcm)292		gus->gf1.pcm_alloc_voices--;293	voice->use = voice->pcm = 0;294	voice->sample_ops = NULL;295	spin_unlock_irqrestore(&gus->voice_alloc, flags);296	if (private_free)297		private_free(voice);298}299 300/*301 *  call this function only by start of driver302 */303 304int snd_gf1_start(struct snd_gus_card * gus)305{306	unsigned long flags;307	unsigned int i;308 309	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0);	/* reset GF1 */310	udelay(160);311	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1);	/* disable IRQ & DAC */312	udelay(160);313	snd_gf1_i_write8(gus, SNDRV_GF1_GB_JOYSTICK_DAC_LEVEL, gus->joystick_dac);314 315	snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_ALL);316	for (i = 0; i < 32; i++) {317		gus->gf1.voices[i].number = i;318		snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_VOICE | i);319	}320 321	snd_gf1_uart_cmd(gus, 0x03);	/* huh.. this cleanup took me some time... */322 323	if (gus->gf1.enh_mode) {	/* enhanced mode !!!! */324		snd_gf1_i_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_i_look8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01);325		snd_gf1_i_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);326	}327	snd_gf1_clear_regs(gus);328	snd_gf1_select_active_voices(gus);329	snd_gf1_delay(gus);330	gus->gf1.default_voice_address = gus->gf1.memory > 0 ? 0 : 512 - 8;331	/* initialize LFOs & clear LFOs memory */332	if (gus->gf1.enh_mode && gus->gf1.memory) {333		gus->gf1.hw_lfo = 1;334		gus->gf1.default_voice_address += 1024;335	} else {336		gus->gf1.sw_lfo = 1;337	}338#if 0339	snd_gf1_lfo_init(gus);340#endif341	if (gus->gf1.memory > 0)342		for (i = 0; i < 4; i++)343			snd_gf1_poke(gus, gus->gf1.default_voice_address + i, 0);344	snd_gf1_clear_regs(gus);345	snd_gf1_clear_voices(gus, 0, 31);346	snd_gf1_look_regs(gus);347	udelay(160);348	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 7);	/* Reset Register = IRQ enable, DAC enable */349	udelay(160);350	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 7);	/* Reset Register = IRQ enable, DAC enable */351	if (gus->gf1.enh_mode) {	/* enhanced mode !!!! */352		snd_gf1_i_write8(gus, SNDRV_GF1_GB_GLOBAL_MODE, snd_gf1_i_look8(gus, SNDRV_GF1_GB_GLOBAL_MODE) | 0x01);353		snd_gf1_i_write8(gus, SNDRV_GF1_GB_MEMORY_CONTROL, 0x01);354	}355	while ((snd_gf1_i_read8(gus, SNDRV_GF1_GB_VOICES_IRQ) & 0xc0) != 0xc0);356 357	spin_lock_irqsave(&gus->reg_lock, flags);358	outb(gus->gf1.active_voice = 0, GUSP(gus, GF1PAGE));359	outb(gus->mix_cntrl_reg, GUSP(gus, MIXCNTRLREG));360	spin_unlock_irqrestore(&gus->reg_lock, flags);361 362	snd_gf1_timers_init(gus);363	snd_gf1_look_regs(gus);364	snd_gf1_mem_init(gus);365	snd_gf1_mem_proc_init(gus);366#ifdef CONFIG_SND_DEBUG367	snd_gus_irq_profile_init(gus);368#endif369 370#if 0371	if (gus->pnp_flag) {372		if (gus->chip.playback_fifo_size > 0)373			snd_gf1_i_write16(gus, SNDRV_GF1_GW_FIFO_RECORD_BASE_ADDR, gus->chip.playback_fifo_block->ptr >> 8);374		if (gus->chip.record_fifo_size > 0)375			snd_gf1_i_write16(gus, SNDRV_GF1_GW_FIFO_PLAY_BASE_ADDR, gus->chip.record_fifo_block->ptr >> 8);376		snd_gf1_i_write16(gus, SNDRV_GF1_GW_FIFO_SIZE, gus->chip.interwave_fifo_reg);377	}378#endif379 380	return 0;381}382 383/*384 *  call this function only by shutdown of driver385 */386 387int snd_gf1_stop(struct snd_gus_card * gus)388{389	snd_gf1_i_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, 0); /* stop all timers */390	snd_gf1_stop_voices(gus, 0, 31);		/* stop all voices */391	snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1);	/* disable IRQ & DAC */392	snd_gf1_timers_done(gus);393	snd_gf1_mem_done(gus);394#if 0395	snd_gf1_lfo_done(gus);396#endif397	return 0;398}399