18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
48c2ecf20Sopenharmony_ci *     and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
58c2ecf20Sopenharmony_ci *  Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  Routines for control of EMU8000 chip
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/wait.h>
118c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/ioport.h>
148c2ecf20Sopenharmony_ci#include <linux/export.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <sound/core.h>
188c2ecf20Sopenharmony_ci#include <sound/emu8000.h>
198c2ecf20Sopenharmony_ci#include <sound/emu8000_reg.h>
208c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
218c2ecf20Sopenharmony_ci#include <linux/init.h>
228c2ecf20Sopenharmony_ci#include <sound/control.h>
238c2ecf20Sopenharmony_ci#include <sound/initval.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * emu8000 register controls
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * The following routines read and write registers on the emu8000.  They
318c2ecf20Sopenharmony_ci * should always be called via the EMU8000*READ/WRITE macros and never
328c2ecf20Sopenharmony_ci * directly.  The macros handle the port number and command word.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci/* Write a word */
358c2ecf20Sopenharmony_civoid snd_emu8000_poke(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	unsigned long flags;
388c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
398c2ecf20Sopenharmony_ci	if (reg != emu->last_reg) {
408c2ecf20Sopenharmony_ci		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
418c2ecf20Sopenharmony_ci		emu->last_reg = reg;
428c2ecf20Sopenharmony_ci	}
438c2ecf20Sopenharmony_ci	outw((unsigned short)val, port); /* Send data */
448c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* Read a word */
488c2ecf20Sopenharmony_ciunsigned short snd_emu8000_peek(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	unsigned short res;
518c2ecf20Sopenharmony_ci	unsigned long flags;
528c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
538c2ecf20Sopenharmony_ci	if (reg != emu->last_reg) {
548c2ecf20Sopenharmony_ci		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
558c2ecf20Sopenharmony_ci		emu->last_reg = reg;
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci	res = inw(port);	/* Read data */
588c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
598c2ecf20Sopenharmony_ci	return res;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Write a double word */
638c2ecf20Sopenharmony_civoid snd_emu8000_poke_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	unsigned long flags;
668c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
678c2ecf20Sopenharmony_ci	if (reg != emu->last_reg) {
688c2ecf20Sopenharmony_ci		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
698c2ecf20Sopenharmony_ci		emu->last_reg = reg;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci	outw((unsigned short)val, port); /* Send low word of data */
728c2ecf20Sopenharmony_ci	outw((unsigned short)(val>>16), port+2); /* Send high word of data */
738c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* Read a double word */
778c2ecf20Sopenharmony_ciunsigned int snd_emu8000_peek_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	unsigned short low;
808c2ecf20Sopenharmony_ci	unsigned int res;
818c2ecf20Sopenharmony_ci	unsigned long flags;
828c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
838c2ecf20Sopenharmony_ci	if (reg != emu->last_reg) {
848c2ecf20Sopenharmony_ci		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
858c2ecf20Sopenharmony_ci		emu->last_reg = reg;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci	low = inw(port);	/* Read low word of data */
888c2ecf20Sopenharmony_ci	res = low + (inw(port+2) << 16);
898c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
908c2ecf20Sopenharmony_ci	return res;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/*
948c2ecf20Sopenharmony_ci * Set up / close a channel to be used for DMA.
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_ci/*exported*/ void
978c2ecf20Sopenharmony_cisnd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	unsigned right_bit = (mode & EMU8000_RAM_RIGHT) ? 0x01000000 : 0;
1008c2ecf20Sopenharmony_ci	mode &= EMU8000_RAM_MODE_MASK;
1018c2ecf20Sopenharmony_ci	if (mode == EMU8000_RAM_CLOSE) {
1028c2ecf20Sopenharmony_ci		EMU8000_CCCA_WRITE(emu, ch, 0);
1038c2ecf20Sopenharmony_ci		EMU8000_DCYSUSV_WRITE(emu, ch, 0x807F);
1048c2ecf20Sopenharmony_ci		return;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci	EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
1078c2ecf20Sopenharmony_ci	EMU8000_VTFT_WRITE(emu, ch, 0);
1088c2ecf20Sopenharmony_ci	EMU8000_CVCF_WRITE(emu, ch, 0);
1098c2ecf20Sopenharmony_ci	EMU8000_PTRX_WRITE(emu, ch, 0x40000000);
1108c2ecf20Sopenharmony_ci	EMU8000_CPF_WRITE(emu, ch, 0x40000000);
1118c2ecf20Sopenharmony_ci	EMU8000_PSST_WRITE(emu, ch, 0);
1128c2ecf20Sopenharmony_ci	EMU8000_CSL_WRITE(emu, ch, 0);
1138c2ecf20Sopenharmony_ci	if (mode == EMU8000_RAM_WRITE) /* DMA write */
1148c2ecf20Sopenharmony_ci		EMU8000_CCCA_WRITE(emu, ch, 0x06000000 | right_bit);
1158c2ecf20Sopenharmony_ci	else	   /* DMA read */
1168c2ecf20Sopenharmony_ci		EMU8000_CCCA_WRITE(emu, ch, 0x04000000 | right_bit);
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/*
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_cistatic void
1228c2ecf20Sopenharmony_cisnd_emu8000_read_wait(struct snd_emu8000 *emu)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
1258c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(1);
1268c2ecf20Sopenharmony_ci		if (signal_pending(current))
1278c2ecf20Sopenharmony_ci			break;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/*
1328c2ecf20Sopenharmony_ci */
1338c2ecf20Sopenharmony_cistatic void
1348c2ecf20Sopenharmony_cisnd_emu8000_write_wait(struct snd_emu8000 *emu)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
1378c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(1);
1388c2ecf20Sopenharmony_ci		if (signal_pending(current))
1398c2ecf20Sopenharmony_ci			break;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/*
1448c2ecf20Sopenharmony_ci * detect a card at the given port
1458c2ecf20Sopenharmony_ci */
1468c2ecf20Sopenharmony_cistatic int
1478c2ecf20Sopenharmony_cisnd_emu8000_detect(struct snd_emu8000 *emu)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	/* Initialise */
1508c2ecf20Sopenharmony_ci	EMU8000_HWCF1_WRITE(emu, 0x0059);
1518c2ecf20Sopenharmony_ci	EMU8000_HWCF2_WRITE(emu, 0x0020);
1528c2ecf20Sopenharmony_ci	EMU8000_HWCF3_WRITE(emu, 0x0000);
1538c2ecf20Sopenharmony_ci	/* Check for a recognisable emu8000 */
1548c2ecf20Sopenharmony_ci	/*
1558c2ecf20Sopenharmony_ci	if ((EMU8000_U1_READ(emu) & 0x000f) != 0x000c)
1568c2ecf20Sopenharmony_ci		return -ENODEV;
1578c2ecf20Sopenharmony_ci		*/
1588c2ecf20Sopenharmony_ci	if ((EMU8000_HWCF1_READ(emu) & 0x007e) != 0x0058)
1598c2ecf20Sopenharmony_ci		return -ENODEV;
1608c2ecf20Sopenharmony_ci	if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)
1618c2ecf20Sopenharmony_ci		return -ENODEV;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",
1648c2ecf20Sopenharmony_ci                    emu->port1);
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/*
1708c2ecf20Sopenharmony_ci * intiailize audio channels
1718c2ecf20Sopenharmony_ci */
1728c2ecf20Sopenharmony_cistatic void
1738c2ecf20Sopenharmony_ciinit_audio(struct snd_emu8000 *emu)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	int ch;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* turn off envelope engines */
1788c2ecf20Sopenharmony_ci	for (ch = 0; ch < EMU8000_CHANNELS; ch++)
1798c2ecf20Sopenharmony_ci		EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	/* reset all other parameters to zero */
1828c2ecf20Sopenharmony_ci	for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
1838c2ecf20Sopenharmony_ci		EMU8000_ENVVOL_WRITE(emu, ch, 0);
1848c2ecf20Sopenharmony_ci		EMU8000_ENVVAL_WRITE(emu, ch, 0);
1858c2ecf20Sopenharmony_ci		EMU8000_DCYSUS_WRITE(emu, ch, 0);
1868c2ecf20Sopenharmony_ci		EMU8000_ATKHLDV_WRITE(emu, ch, 0);
1878c2ecf20Sopenharmony_ci		EMU8000_LFO1VAL_WRITE(emu, ch, 0);
1888c2ecf20Sopenharmony_ci		EMU8000_ATKHLD_WRITE(emu, ch, 0);
1898c2ecf20Sopenharmony_ci		EMU8000_LFO2VAL_WRITE(emu, ch, 0);
1908c2ecf20Sopenharmony_ci		EMU8000_IP_WRITE(emu, ch, 0);
1918c2ecf20Sopenharmony_ci		EMU8000_IFATN_WRITE(emu, ch, 0);
1928c2ecf20Sopenharmony_ci		EMU8000_PEFE_WRITE(emu, ch, 0);
1938c2ecf20Sopenharmony_ci		EMU8000_FMMOD_WRITE(emu, ch, 0);
1948c2ecf20Sopenharmony_ci		EMU8000_TREMFRQ_WRITE(emu, ch, 0);
1958c2ecf20Sopenharmony_ci		EMU8000_FM2FRQ2_WRITE(emu, ch, 0);
1968c2ecf20Sopenharmony_ci		EMU8000_PTRX_WRITE(emu, ch, 0);
1978c2ecf20Sopenharmony_ci		EMU8000_VTFT_WRITE(emu, ch, 0);
1988c2ecf20Sopenharmony_ci		EMU8000_PSST_WRITE(emu, ch, 0);
1998c2ecf20Sopenharmony_ci		EMU8000_CSL_WRITE(emu, ch, 0);
2008c2ecf20Sopenharmony_ci		EMU8000_CCCA_WRITE(emu, ch, 0);
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
2048c2ecf20Sopenharmony_ci		EMU8000_CPF_WRITE(emu, ch, 0);
2058c2ecf20Sopenharmony_ci		EMU8000_CVCF_WRITE(emu, ch, 0);
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci * initialize DMA address
2128c2ecf20Sopenharmony_ci */
2138c2ecf20Sopenharmony_cistatic void
2148c2ecf20Sopenharmony_ciinit_dma(struct snd_emu8000 *emu)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	EMU8000_SMALR_WRITE(emu, 0);
2178c2ecf20Sopenharmony_ci	EMU8000_SMARR_WRITE(emu, 0);
2188c2ecf20Sopenharmony_ci	EMU8000_SMALW_WRITE(emu, 0);
2198c2ecf20Sopenharmony_ci	EMU8000_SMARW_WRITE(emu, 0);
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci/*
2238c2ecf20Sopenharmony_ci * initialization arrays; from ADIP
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic const unsigned short init1[128] = {
2268c2ecf20Sopenharmony_ci	0x03ff, 0x0030,  0x07ff, 0x0130, 0x0bff, 0x0230,  0x0fff, 0x0330,
2278c2ecf20Sopenharmony_ci	0x13ff, 0x0430,  0x17ff, 0x0530, 0x1bff, 0x0630,  0x1fff, 0x0730,
2288c2ecf20Sopenharmony_ci	0x23ff, 0x0830,  0x27ff, 0x0930, 0x2bff, 0x0a30,  0x2fff, 0x0b30,
2298c2ecf20Sopenharmony_ci	0x33ff, 0x0c30,  0x37ff, 0x0d30, 0x3bff, 0x0e30,  0x3fff, 0x0f30,
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	0x43ff, 0x0030,  0x47ff, 0x0130, 0x4bff, 0x0230,  0x4fff, 0x0330,
2328c2ecf20Sopenharmony_ci	0x53ff, 0x0430,  0x57ff, 0x0530, 0x5bff, 0x0630,  0x5fff, 0x0730,
2338c2ecf20Sopenharmony_ci	0x63ff, 0x0830,  0x67ff, 0x0930, 0x6bff, 0x0a30,  0x6fff, 0x0b30,
2348c2ecf20Sopenharmony_ci	0x73ff, 0x0c30,  0x77ff, 0x0d30, 0x7bff, 0x0e30,  0x7fff, 0x0f30,
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	0x83ff, 0x0030,  0x87ff, 0x0130, 0x8bff, 0x0230,  0x8fff, 0x0330,
2378c2ecf20Sopenharmony_ci	0x93ff, 0x0430,  0x97ff, 0x0530, 0x9bff, 0x0630,  0x9fff, 0x0730,
2388c2ecf20Sopenharmony_ci	0xa3ff, 0x0830,  0xa7ff, 0x0930, 0xabff, 0x0a30,  0xafff, 0x0b30,
2398c2ecf20Sopenharmony_ci	0xb3ff, 0x0c30,  0xb7ff, 0x0d30, 0xbbff, 0x0e30,  0xbfff, 0x0f30,
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	0xc3ff, 0x0030,  0xc7ff, 0x0130, 0xcbff, 0x0230,  0xcfff, 0x0330,
2428c2ecf20Sopenharmony_ci	0xd3ff, 0x0430,  0xd7ff, 0x0530, 0xdbff, 0x0630,  0xdfff, 0x0730,
2438c2ecf20Sopenharmony_ci	0xe3ff, 0x0830,  0xe7ff, 0x0930, 0xebff, 0x0a30,  0xefff, 0x0b30,
2448c2ecf20Sopenharmony_ci	0xf3ff, 0x0c30,  0xf7ff, 0x0d30, 0xfbff, 0x0e30,  0xffff, 0x0f30,
2458c2ecf20Sopenharmony_ci};
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic const unsigned short init2[128] = {
2488c2ecf20Sopenharmony_ci	0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
2498c2ecf20Sopenharmony_ci	0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
2508c2ecf20Sopenharmony_ci	0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
2518c2ecf20Sopenharmony_ci	0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
2548c2ecf20Sopenharmony_ci	0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
2558c2ecf20Sopenharmony_ci	0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
2568c2ecf20Sopenharmony_ci	0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
2598c2ecf20Sopenharmony_ci	0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
2608c2ecf20Sopenharmony_ci	0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
2618c2ecf20Sopenharmony_ci	0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
2648c2ecf20Sopenharmony_ci	0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
2658c2ecf20Sopenharmony_ci	0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
2668c2ecf20Sopenharmony_ci	0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
2678c2ecf20Sopenharmony_ci};
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic const unsigned short init3[128] = {
2708c2ecf20Sopenharmony_ci	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
2718c2ecf20Sopenharmony_ci	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
2728c2ecf20Sopenharmony_ci	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
2738c2ecf20Sopenharmony_ci	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
2768c2ecf20Sopenharmony_ci	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
2778c2ecf20Sopenharmony_ci	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
2788c2ecf20Sopenharmony_ci	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
2818c2ecf20Sopenharmony_ci	0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
2828c2ecf20Sopenharmony_ci	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
2838c2ecf20Sopenharmony_ci	0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
2868c2ecf20Sopenharmony_ci	0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
2878c2ecf20Sopenharmony_ci	0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
2888c2ecf20Sopenharmony_ci	0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic const unsigned short init4[128] = {
2928c2ecf20Sopenharmony_ci	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
2938c2ecf20Sopenharmony_ci	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
2948c2ecf20Sopenharmony_ci	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
2958c2ecf20Sopenharmony_ci	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
2988c2ecf20Sopenharmony_ci	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
2998c2ecf20Sopenharmony_ci	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
3008c2ecf20Sopenharmony_ci	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
3038c2ecf20Sopenharmony_ci	0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
3048c2ecf20Sopenharmony_ci	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
3058c2ecf20Sopenharmony_ci	0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
3088c2ecf20Sopenharmony_ci	0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
3098c2ecf20Sopenharmony_ci	0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
3108c2ecf20Sopenharmony_ci	0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
3118c2ecf20Sopenharmony_ci};
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci/* send an initialization array
3148c2ecf20Sopenharmony_ci * Taken from the oss driver, not obvious from the doc how this
3158c2ecf20Sopenharmony_ci * is meant to work
3168c2ecf20Sopenharmony_ci */
3178c2ecf20Sopenharmony_cistatic void
3188c2ecf20Sopenharmony_cisend_array(struct snd_emu8000 *emu, const unsigned short *data, int size)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	int i;
3218c2ecf20Sopenharmony_ci	const unsigned short *p;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	p = data;
3248c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++, p++)
3258c2ecf20Sopenharmony_ci		EMU8000_INIT1_WRITE(emu, i, *p);
3268c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++, p++)
3278c2ecf20Sopenharmony_ci		EMU8000_INIT2_WRITE(emu, i, *p);
3288c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++, p++)
3298c2ecf20Sopenharmony_ci		EMU8000_INIT3_WRITE(emu, i, *p);
3308c2ecf20Sopenharmony_ci	for (i = 0; i < size; i++, p++)
3318c2ecf20Sopenharmony_ci		EMU8000_INIT4_WRITE(emu, i, *p);
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/*
3368c2ecf20Sopenharmony_ci * Send initialization arrays to start up, this just follows the
3378c2ecf20Sopenharmony_ci * initialisation sequence in the adip.
3388c2ecf20Sopenharmony_ci */
3398c2ecf20Sopenharmony_cistatic void
3408c2ecf20Sopenharmony_ciinit_arrays(struct snd_emu8000 *emu)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	send_array(emu, init1, ARRAY_SIZE(init1)/4);
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
3458c2ecf20Sopenharmony_ci	send_array(emu, init2, ARRAY_SIZE(init2)/4);
3468c2ecf20Sopenharmony_ci	send_array(emu, init3, ARRAY_SIZE(init3)/4);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	EMU8000_HWCF4_WRITE(emu, 0);
3498c2ecf20Sopenharmony_ci	EMU8000_HWCF5_WRITE(emu, 0x83);
3508c2ecf20Sopenharmony_ci	EMU8000_HWCF6_WRITE(emu, 0x8000);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	send_array(emu, init4, ARRAY_SIZE(init4)/4);
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci#define UNIQUE_ID1	0xa5b9
3578c2ecf20Sopenharmony_ci#define UNIQUE_ID2	0x9d53
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci/*
3608c2ecf20Sopenharmony_ci * Size the onboard memory.
3618c2ecf20Sopenharmony_ci * This is written so as not to need arbitrary delays after the write. It
3628c2ecf20Sopenharmony_ci * seems that the only way to do this is to use the one channel and keep
3638c2ecf20Sopenharmony_ci * reallocating between read and write.
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_cistatic void
3668c2ecf20Sopenharmony_cisize_dram(struct snd_emu8000 *emu)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	int i, size;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (emu->dram_checked)
3718c2ecf20Sopenharmony_ci		return;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	size = 0;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* write out a magic number */
3768c2ecf20Sopenharmony_ci	snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
3778c2ecf20Sopenharmony_ci	snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_READ);
3788c2ecf20Sopenharmony_ci	EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
3798c2ecf20Sopenharmony_ci	EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
3808c2ecf20Sopenharmony_ci	snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
3818c2ecf20Sopenharmony_ci	snd_emu8000_write_wait(emu);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/*
3848c2ecf20Sopenharmony_ci	 * Detect first 512 KiB.  If a write succeeds at the beginning of a
3858c2ecf20Sopenharmony_ci	 * 512 KiB page we assume that the whole page is there.
3868c2ecf20Sopenharmony_ci	 */
3878c2ecf20Sopenharmony_ci	EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
3888c2ecf20Sopenharmony_ci	EMU8000_SMLD_READ(emu); /* discard stale data  */
3898c2ecf20Sopenharmony_ci	if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
3908c2ecf20Sopenharmony_ci		goto skip_detect;   /* No RAM */
3918c2ecf20Sopenharmony_ci	snd_emu8000_read_wait(emu);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) {
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		/* Write a unique data on the test address.
3968c2ecf20Sopenharmony_ci		 * if the address is out of range, the data is written on
3978c2ecf20Sopenharmony_ci		 * 0x200000(=EMU8000_DRAM_OFFSET).  Then the id word is
3988c2ecf20Sopenharmony_ci		 * changed by this data.
3998c2ecf20Sopenharmony_ci		 */
4008c2ecf20Sopenharmony_ci		/*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
4018c2ecf20Sopenharmony_ci		EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
4028c2ecf20Sopenharmony_ci		EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
4038c2ecf20Sopenharmony_ci		snd_emu8000_write_wait(emu);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		/*
4068c2ecf20Sopenharmony_ci		 * read the data on the just written DRAM address
4078c2ecf20Sopenharmony_ci		 * if not the same then we have reached the end of ram.
4088c2ecf20Sopenharmony_ci		 */
4098c2ecf20Sopenharmony_ci		/*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
4108c2ecf20Sopenharmony_ci		EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
4118c2ecf20Sopenharmony_ci		/*snd_emu8000_read_wait(emu);*/
4128c2ecf20Sopenharmony_ci		EMU8000_SMLD_READ(emu); /* discard stale data  */
4138c2ecf20Sopenharmony_ci		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
4148c2ecf20Sopenharmony_ci			break; /* no memory at this address */
4158c2ecf20Sopenharmony_ci		snd_emu8000_read_wait(emu);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		/*
4188c2ecf20Sopenharmony_ci		 * If it is the same it could be that the address just
4198c2ecf20Sopenharmony_ci		 * wraps back to the beginning; so check to see if the
4208c2ecf20Sopenharmony_ci		 * initial value has been overwritten.
4218c2ecf20Sopenharmony_ci		 */
4228c2ecf20Sopenharmony_ci		EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
4238c2ecf20Sopenharmony_ci		EMU8000_SMLD_READ(emu); /* discard stale data  */
4248c2ecf20Sopenharmony_ci		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
4258c2ecf20Sopenharmony_ci			break; /* we must have wrapped around */
4268c2ecf20Sopenharmony_ci		snd_emu8000_read_wait(emu);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		/* Otherwise, it's valid memory. */
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciskip_detect:
4328c2ecf20Sopenharmony_ci	/* wait until FULL bit in SMAxW register is false */
4338c2ecf20Sopenharmony_ci	for (i = 0; i < 10000; i++) {
4348c2ecf20Sopenharmony_ci		if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
4358c2ecf20Sopenharmony_ci			break;
4368c2ecf20Sopenharmony_ci		schedule_timeout_interruptible(1);
4378c2ecf20Sopenharmony_ci		if (signal_pending(current))
4388c2ecf20Sopenharmony_ci			break;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci	snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
4418c2ecf20Sopenharmony_ci	snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n",
4448c2ecf20Sopenharmony_ci		    emu->port1, size/1024);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	emu->mem_size = size;
4478c2ecf20Sopenharmony_ci	emu->dram_checked = 1;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci/*
4528c2ecf20Sopenharmony_ci * Initiailise the FM section.  You have to do this to use sample RAM
4538c2ecf20Sopenharmony_ci * and therefore lose 2 voices.
4548c2ecf20Sopenharmony_ci */
4558c2ecf20Sopenharmony_ci/*exported*/ void
4568c2ecf20Sopenharmony_cisnd_emu8000_init_fm(struct snd_emu8000 *emu)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	unsigned long flags;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* Initialize the last two channels for DRAM refresh and producing
4618c2ecf20Sopenharmony_ci	   the reverb and chorus effects for Yamaha OPL-3 synthesizer */
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/* 31: FM left channel, 0xffffe0-0xffffe8 */
4648c2ecf20Sopenharmony_ci	EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
4658c2ecf20Sopenharmony_ci	EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
4668c2ecf20Sopenharmony_ci	EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
4678c2ecf20Sopenharmony_ci	EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
4688c2ecf20Sopenharmony_ci	EMU8000_CPF_WRITE(emu, 30, 0);
4698c2ecf20Sopenharmony_ci	EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* 32: FM right channel, 0xfffff0-0xfffff8 */
4728c2ecf20Sopenharmony_ci	EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
4738c2ecf20Sopenharmony_ci	EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
4748c2ecf20Sopenharmony_ci	EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
4758c2ecf20Sopenharmony_ci	EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
4768c2ecf20Sopenharmony_ci	EMU8000_CPF_WRITE(emu, 31, 0x8000);
4778c2ecf20Sopenharmony_ci	EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->reg_lock, flags);
4828c2ecf20Sopenharmony_ci	while (!(inw(EMU8000_PTR(emu)) & 0x1000))
4838c2ecf20Sopenharmony_ci		;
4848c2ecf20Sopenharmony_ci	while ((inw(EMU8000_PTR(emu)) & 0x1000))
4858c2ecf20Sopenharmony_ci		;
4868c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->reg_lock, flags);
4878c2ecf20Sopenharmony_ci	snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
4888c2ecf20Sopenharmony_ci	/* this is really odd part.. */
4898c2ecf20Sopenharmony_ci	outb(0x3C, EMU8000_PTR(emu));
4908c2ecf20Sopenharmony_ci	outb(0, EMU8000_DATA1(emu));
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* skew volume & cutoff */
4938c2ecf20Sopenharmony_ci	EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
4948c2ecf20Sopenharmony_ci	EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci/*
4998c2ecf20Sopenharmony_ci * The main initialization routine.
5008c2ecf20Sopenharmony_ci */
5018c2ecf20Sopenharmony_cistatic void
5028c2ecf20Sopenharmony_cisnd_emu8000_init_hw(struct snd_emu8000 *emu)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	int i;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	emu->last_reg = 0xffff; /* reset the last register index */
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	/* initialize hardware configuration */
5098c2ecf20Sopenharmony_ci	EMU8000_HWCF1_WRITE(emu, 0x0059);
5108c2ecf20Sopenharmony_ci	EMU8000_HWCF2_WRITE(emu, 0x0020);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	/* disable audio; this seems to reduce a clicking noise a bit.. */
5138c2ecf20Sopenharmony_ci	EMU8000_HWCF3_WRITE(emu, 0);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	/* initialize audio channels */
5168c2ecf20Sopenharmony_ci	init_audio(emu);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* initialize DMA */
5198c2ecf20Sopenharmony_ci	init_dma(emu);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	/* initialize init arrays */
5228c2ecf20Sopenharmony_ci	init_arrays(emu);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/*
5258c2ecf20Sopenharmony_ci	 * Initialize the FM section of the AWE32, this is needed
5268c2ecf20Sopenharmony_ci	 * for DRAM refresh as well
5278c2ecf20Sopenharmony_ci	 */
5288c2ecf20Sopenharmony_ci	snd_emu8000_init_fm(emu);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	/* terminate all voices */
5318c2ecf20Sopenharmony_ci	for (i = 0; i < EMU8000_DRAM_VOICES; i++)
5328c2ecf20Sopenharmony_ci		EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	/* check DRAM memory size */
5358c2ecf20Sopenharmony_ci	size_dram(emu);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	/* enable audio */
5388c2ecf20Sopenharmony_ci	EMU8000_HWCF3_WRITE(emu, 0x4);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* set equzlier, chorus and reverb modes */
5418c2ecf20Sopenharmony_ci	snd_emu8000_update_equalizer(emu);
5428c2ecf20Sopenharmony_ci	snd_emu8000_update_chorus_mode(emu);
5438c2ecf20Sopenharmony_ci	snd_emu8000_update_reverb_mode(emu);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/*----------------------------------------------------------------
5488c2ecf20Sopenharmony_ci * Bass/Treble Equalizer
5498c2ecf20Sopenharmony_ci *----------------------------------------------------------------*/
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic const unsigned short bass_parm[12][3] = {
5528c2ecf20Sopenharmony_ci	{0xD26A, 0xD36A, 0x0000}, /* -12 dB */
5538c2ecf20Sopenharmony_ci	{0xD25B, 0xD35B, 0x0000}, /*  -8 */
5548c2ecf20Sopenharmony_ci	{0xD24C, 0xD34C, 0x0000}, /*  -6 */
5558c2ecf20Sopenharmony_ci	{0xD23D, 0xD33D, 0x0000}, /*  -4 */
5568c2ecf20Sopenharmony_ci	{0xD21F, 0xD31F, 0x0000}, /*  -2 */
5578c2ecf20Sopenharmony_ci	{0xC208, 0xC308, 0x0001}, /*   0 (HW default) */
5588c2ecf20Sopenharmony_ci	{0xC219, 0xC319, 0x0001}, /*  +2 */
5598c2ecf20Sopenharmony_ci	{0xC22A, 0xC32A, 0x0001}, /*  +4 */
5608c2ecf20Sopenharmony_ci	{0xC24C, 0xC34C, 0x0001}, /*  +6 */
5618c2ecf20Sopenharmony_ci	{0xC26E, 0xC36E, 0x0001}, /*  +8 */
5628c2ecf20Sopenharmony_ci	{0xC248, 0xC384, 0x0002}, /* +10 */
5638c2ecf20Sopenharmony_ci	{0xC26A, 0xC36A, 0x0002}, /* +12 dB */
5648c2ecf20Sopenharmony_ci};
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic const unsigned short treble_parm[12][9] = {
5678c2ecf20Sopenharmony_ci	{0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
5688c2ecf20Sopenharmony_ci	{0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
5698c2ecf20Sopenharmony_ci	{0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
5708c2ecf20Sopenharmony_ci	{0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
5718c2ecf20Sopenharmony_ci	{0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
5728c2ecf20Sopenharmony_ci	{0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
5738c2ecf20Sopenharmony_ci	{0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
5748c2ecf20Sopenharmony_ci	{0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
5758c2ecf20Sopenharmony_ci	{0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
5768c2ecf20Sopenharmony_ci	{0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
5778c2ecf20Sopenharmony_ci	{0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
5788c2ecf20Sopenharmony_ci	{0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}  /* +12 dB */
5798c2ecf20Sopenharmony_ci};
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci/*
5838c2ecf20Sopenharmony_ci * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
5848c2ecf20Sopenharmony_ci */
5858c2ecf20Sopenharmony_ci/*exported*/ void
5868c2ecf20Sopenharmony_cisnd_emu8000_update_equalizer(struct snd_emu8000 *emu)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	unsigned short w;
5898c2ecf20Sopenharmony_ci	int bass = emu->bass_level;
5908c2ecf20Sopenharmony_ci	int treble = emu->treble_level;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
5938c2ecf20Sopenharmony_ci		return;
5948c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
5958c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
5968c2ecf20Sopenharmony_ci	EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
5978c2ecf20Sopenharmony_ci	EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
5988c2ecf20Sopenharmony_ci	EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
5998c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
6008c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
6018c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
6028c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
6038c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
6048c2ecf20Sopenharmony_ci	w = bass_parm[bass][2] + treble_parm[treble][8];
6058c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
6068c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci/*----------------------------------------------------------------
6118c2ecf20Sopenharmony_ci * Chorus mode control
6128c2ecf20Sopenharmony_ci *----------------------------------------------------------------*/
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci/*
6158c2ecf20Sopenharmony_ci * chorus mode parameters
6168c2ecf20Sopenharmony_ci */
6178c2ecf20Sopenharmony_ci#define SNDRV_EMU8000_CHORUS_1		0
6188c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_2		1
6198c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_3		2
6208c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_4		3
6218c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_FEEDBACK	4
6228c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_FLANGER	5
6238c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_SHORTDELAY	6
6248c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_CHORUS_SHORTDELAY2	7
6258c2ecf20Sopenharmony_ci#define SNDRV_EMU8000_CHORUS_PREDEFINED	8
6268c2ecf20Sopenharmony_ci/* user can define chorus modes up to 32 */
6278c2ecf20Sopenharmony_ci#define SNDRV_EMU8000_CHORUS_NUMBERS	32
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistruct soundfont_chorus_fx {
6308c2ecf20Sopenharmony_ci	unsigned short feedback;	/* feedback level (0xE600-0xE6FF) */
6318c2ecf20Sopenharmony_ci	unsigned short delay_offset;	/* delay (0-0x0DA3) [1/44100 sec] */
6328c2ecf20Sopenharmony_ci	unsigned short lfo_depth;	/* LFO depth (0xBC00-0xBCFF) */
6338c2ecf20Sopenharmony_ci	unsigned int delay;	/* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
6348c2ecf20Sopenharmony_ci	unsigned int lfo_freq;		/* LFO freq LFO freq (0-0xFFFFFFFF) */
6358c2ecf20Sopenharmony_ci};
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
6388c2ecf20Sopenharmony_cistatic char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
6398c2ecf20Sopenharmony_cistatic struct soundfont_chorus_fx chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
6408c2ecf20Sopenharmony_ci	{0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
6418c2ecf20Sopenharmony_ci	{0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
6428c2ecf20Sopenharmony_ci	{0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
6438c2ecf20Sopenharmony_ci	{0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
6448c2ecf20Sopenharmony_ci	{0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
6458c2ecf20Sopenharmony_ci	{0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
6468c2ecf20Sopenharmony_ci	{0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
6478c2ecf20Sopenharmony_ci	{0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
6488c2ecf20Sopenharmony_ci};
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/*exported*/ int
6518c2ecf20Sopenharmony_cisnd_emu8000_load_chorus_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	struct soundfont_chorus_fx rec;
6548c2ecf20Sopenharmony_ci	if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
6558c2ecf20Sopenharmony_ci		snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
6568c2ecf20Sopenharmony_ci		return -EINVAL;
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci	if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
6598c2ecf20Sopenharmony_ci		return -EFAULT;
6608c2ecf20Sopenharmony_ci	chorus_parm[mode] = rec;
6618c2ecf20Sopenharmony_ci	chorus_defined[mode] = 1;
6628c2ecf20Sopenharmony_ci	return 0;
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci/*exported*/ void
6668c2ecf20Sopenharmony_cisnd_emu8000_update_chorus_mode(struct snd_emu8000 *emu)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	int effect = emu->chorus_mode;
6698c2ecf20Sopenharmony_ci	if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
6708c2ecf20Sopenharmony_ci	    (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
6718c2ecf20Sopenharmony_ci		return;
6728c2ecf20Sopenharmony_ci	EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
6738c2ecf20Sopenharmony_ci	EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
6748c2ecf20Sopenharmony_ci	EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
6758c2ecf20Sopenharmony_ci	EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
6768c2ecf20Sopenharmony_ci	EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
6778c2ecf20Sopenharmony_ci	EMU8000_HWCF6_WRITE(emu, 0x8000);
6788c2ecf20Sopenharmony_ci	EMU8000_HWCF7_WRITE(emu, 0x0000);
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci/*----------------------------------------------------------------
6828c2ecf20Sopenharmony_ci * Reverb mode control
6838c2ecf20Sopenharmony_ci *----------------------------------------------------------------*/
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci/*
6868c2ecf20Sopenharmony_ci * reverb mode parameters
6878c2ecf20Sopenharmony_ci */
6888c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_ROOM1	0
6898c2ecf20Sopenharmony_ci#define SNDRV_EMU8000_REVERB_ROOM2	1
6908c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_ROOM3	2
6918c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_HALL1	3
6928c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_HALL2	4
6938c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_PLATE	5
6948c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_DELAY	6
6958c2ecf20Sopenharmony_ci#define	SNDRV_EMU8000_REVERB_PANNINGDELAY 7
6968c2ecf20Sopenharmony_ci#define SNDRV_EMU8000_REVERB_PREDEFINED	8
6978c2ecf20Sopenharmony_ci/* user can define reverb modes up to 32 */
6988c2ecf20Sopenharmony_ci#define SNDRV_EMU8000_REVERB_NUMBERS	32
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistruct soundfont_reverb_fx {
7018c2ecf20Sopenharmony_ci	unsigned short parms[28];
7028c2ecf20Sopenharmony_ci};
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/* reverb mode settings; write the following 28 data of 16 bit length
7058c2ecf20Sopenharmony_ci *   on the corresponding ports in the reverb_cmds array
7068c2ecf20Sopenharmony_ci */
7078c2ecf20Sopenharmony_cistatic char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
7088c2ecf20Sopenharmony_cistatic struct soundfont_reverb_fx reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
7098c2ecf20Sopenharmony_ci{{  /* room 1 */
7108c2ecf20Sopenharmony_ci	0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
7118c2ecf20Sopenharmony_ci	0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
7128c2ecf20Sopenharmony_ci	0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
7138c2ecf20Sopenharmony_ci	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
7148c2ecf20Sopenharmony_ci}},
7158c2ecf20Sopenharmony_ci{{  /* room 2 */
7168c2ecf20Sopenharmony_ci	0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
7178c2ecf20Sopenharmony_ci	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
7188c2ecf20Sopenharmony_ci	0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
7198c2ecf20Sopenharmony_ci	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
7208c2ecf20Sopenharmony_ci}},
7218c2ecf20Sopenharmony_ci{{  /* room 3 */
7228c2ecf20Sopenharmony_ci	0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
7238c2ecf20Sopenharmony_ci	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
7248c2ecf20Sopenharmony_ci	0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
7258c2ecf20Sopenharmony_ci	0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
7268c2ecf20Sopenharmony_ci}},
7278c2ecf20Sopenharmony_ci{{  /* hall 1 */
7288c2ecf20Sopenharmony_ci	0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
7298c2ecf20Sopenharmony_ci	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
7308c2ecf20Sopenharmony_ci	0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
7318c2ecf20Sopenharmony_ci	0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
7328c2ecf20Sopenharmony_ci}},
7338c2ecf20Sopenharmony_ci{{  /* hall 2 */
7348c2ecf20Sopenharmony_ci	0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
7358c2ecf20Sopenharmony_ci	0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
7368c2ecf20Sopenharmony_ci	0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
7378c2ecf20Sopenharmony_ci	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
7388c2ecf20Sopenharmony_ci}},
7398c2ecf20Sopenharmony_ci{{  /* plate */
7408c2ecf20Sopenharmony_ci	0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
7418c2ecf20Sopenharmony_ci	0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
7428c2ecf20Sopenharmony_ci	0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
7438c2ecf20Sopenharmony_ci	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
7448c2ecf20Sopenharmony_ci}},
7458c2ecf20Sopenharmony_ci{{  /* delay */
7468c2ecf20Sopenharmony_ci	0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
7478c2ecf20Sopenharmony_ci	0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
7488c2ecf20Sopenharmony_ci	0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
7498c2ecf20Sopenharmony_ci	0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
7508c2ecf20Sopenharmony_ci}},
7518c2ecf20Sopenharmony_ci{{  /* panning delay */
7528c2ecf20Sopenharmony_ci	0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
7538c2ecf20Sopenharmony_ci	0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
7548c2ecf20Sopenharmony_ci	0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
7558c2ecf20Sopenharmony_ci	0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
7568c2ecf20Sopenharmony_ci}},
7578c2ecf20Sopenharmony_ci};
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cienum { DATA1, DATA2 };
7608c2ecf20Sopenharmony_ci#define AWE_INIT1(c)	EMU8000_CMD(2,c), DATA1
7618c2ecf20Sopenharmony_ci#define AWE_INIT2(c)	EMU8000_CMD(2,c), DATA2
7628c2ecf20Sopenharmony_ci#define AWE_INIT3(c)	EMU8000_CMD(3,c), DATA1
7638c2ecf20Sopenharmony_ci#define AWE_INIT4(c)	EMU8000_CMD(3,c), DATA2
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic struct reverb_cmd_pair {
7668c2ecf20Sopenharmony_ci	unsigned short cmd, port;
7678c2ecf20Sopenharmony_ci} reverb_cmds[28] = {
7688c2ecf20Sopenharmony_ci  {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
7698c2ecf20Sopenharmony_ci  {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
7708c2ecf20Sopenharmony_ci  {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
7718c2ecf20Sopenharmony_ci  {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
7728c2ecf20Sopenharmony_ci  {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
7738c2ecf20Sopenharmony_ci  {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
7748c2ecf20Sopenharmony_ci  {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
7758c2ecf20Sopenharmony_ci};
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci/*exported*/ int
7788c2ecf20Sopenharmony_cisnd_emu8000_load_reverb_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	struct soundfont_reverb_fx rec;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
7838c2ecf20Sopenharmony_ci		snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
7848c2ecf20Sopenharmony_ci		return -EINVAL;
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci	if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
7878c2ecf20Sopenharmony_ci		return -EFAULT;
7888c2ecf20Sopenharmony_ci	reverb_parm[mode] = rec;
7898c2ecf20Sopenharmony_ci	reverb_defined[mode] = 1;
7908c2ecf20Sopenharmony_ci	return 0;
7918c2ecf20Sopenharmony_ci}
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci/*exported*/ void
7948c2ecf20Sopenharmony_cisnd_emu8000_update_reverb_mode(struct snd_emu8000 *emu)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	int effect = emu->reverb_mode;
7978c2ecf20Sopenharmony_ci	int i;
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
8008c2ecf20Sopenharmony_ci	    (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
8018c2ecf20Sopenharmony_ci		return;
8028c2ecf20Sopenharmony_ci	for (i = 0; i < 28; i++) {
8038c2ecf20Sopenharmony_ci		int port;
8048c2ecf20Sopenharmony_ci		if (reverb_cmds[i].port == DATA1)
8058c2ecf20Sopenharmony_ci			port = EMU8000_DATA1(emu);
8068c2ecf20Sopenharmony_ci		else
8078c2ecf20Sopenharmony_ci			port = EMU8000_DATA2(emu);
8088c2ecf20Sopenharmony_ci		snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci/*----------------------------------------------------------------
8148c2ecf20Sopenharmony_ci * mixer interface
8158c2ecf20Sopenharmony_ci *----------------------------------------------------------------*/
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/*
8188c2ecf20Sopenharmony_ci * bass/treble
8198c2ecf20Sopenharmony_ci */
8208c2ecf20Sopenharmony_cistatic int mixer_bass_treble_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
8238c2ecf20Sopenharmony_ci	uinfo->count = 1;
8248c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
8258c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 11;
8268c2ecf20Sopenharmony_ci	return 0;
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
8348c2ecf20Sopenharmony_ci	return 0;
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
8408c2ecf20Sopenharmony_ci	unsigned long flags;
8418c2ecf20Sopenharmony_ci	int change;
8428c2ecf20Sopenharmony_ci	unsigned short val1;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	val1 = ucontrol->value.integer.value[0] % 12;
8458c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->control_lock, flags);
8468c2ecf20Sopenharmony_ci	if (kcontrol->private_value) {
8478c2ecf20Sopenharmony_ci		change = val1 != emu->treble_level;
8488c2ecf20Sopenharmony_ci		emu->treble_level = val1;
8498c2ecf20Sopenharmony_ci	} else {
8508c2ecf20Sopenharmony_ci		change = val1 != emu->bass_level;
8518c2ecf20Sopenharmony_ci		emu->bass_level = val1;
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->control_lock, flags);
8548c2ecf20Sopenharmony_ci	snd_emu8000_update_equalizer(emu);
8558c2ecf20Sopenharmony_ci	return change;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixer_bass_control =
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8618c2ecf20Sopenharmony_ci	.name = "Synth Tone Control - Bass",
8628c2ecf20Sopenharmony_ci	.info = mixer_bass_treble_info,
8638c2ecf20Sopenharmony_ci	.get = mixer_bass_treble_get,
8648c2ecf20Sopenharmony_ci	.put = mixer_bass_treble_put,
8658c2ecf20Sopenharmony_ci	.private_value = 0,
8668c2ecf20Sopenharmony_ci};
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixer_treble_control =
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
8718c2ecf20Sopenharmony_ci	.name = "Synth Tone Control - Treble",
8728c2ecf20Sopenharmony_ci	.info = mixer_bass_treble_info,
8738c2ecf20Sopenharmony_ci	.get = mixer_bass_treble_get,
8748c2ecf20Sopenharmony_ci	.put = mixer_bass_treble_put,
8758c2ecf20Sopenharmony_ci	.private_value = 1,
8768c2ecf20Sopenharmony_ci};
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci/*
8798c2ecf20Sopenharmony_ci * chorus/reverb mode
8808c2ecf20Sopenharmony_ci */
8818c2ecf20Sopenharmony_cistatic int mixer_chorus_reverb_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
8828c2ecf20Sopenharmony_ci{
8838c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
8848c2ecf20Sopenharmony_ci	uinfo->count = 1;
8858c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
8868c2ecf20Sopenharmony_ci	uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
8878c2ecf20Sopenharmony_ci	return 0;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
8958c2ecf20Sopenharmony_ci	return 0;
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_cistatic int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
9018c2ecf20Sopenharmony_ci	unsigned long flags;
9028c2ecf20Sopenharmony_ci	int change;
9038c2ecf20Sopenharmony_ci	unsigned short val1;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->control_lock, flags);
9068c2ecf20Sopenharmony_ci	if (kcontrol->private_value) {
9078c2ecf20Sopenharmony_ci		val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
9088c2ecf20Sopenharmony_ci		change = val1 != emu->chorus_mode;
9098c2ecf20Sopenharmony_ci		emu->chorus_mode = val1;
9108c2ecf20Sopenharmony_ci	} else {
9118c2ecf20Sopenharmony_ci		val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
9128c2ecf20Sopenharmony_ci		change = val1 != emu->reverb_mode;
9138c2ecf20Sopenharmony_ci		emu->reverb_mode = val1;
9148c2ecf20Sopenharmony_ci	}
9158c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->control_lock, flags);
9168c2ecf20Sopenharmony_ci	if (change) {
9178c2ecf20Sopenharmony_ci		if (kcontrol->private_value)
9188c2ecf20Sopenharmony_ci			snd_emu8000_update_chorus_mode(emu);
9198c2ecf20Sopenharmony_ci		else
9208c2ecf20Sopenharmony_ci			snd_emu8000_update_reverb_mode(emu);
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci	return change;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixer_chorus_mode_control =
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9288c2ecf20Sopenharmony_ci	.name = "Chorus Mode",
9298c2ecf20Sopenharmony_ci	.info = mixer_chorus_reverb_info,
9308c2ecf20Sopenharmony_ci	.get = mixer_chorus_reverb_get,
9318c2ecf20Sopenharmony_ci	.put = mixer_chorus_reverb_put,
9328c2ecf20Sopenharmony_ci	.private_value = 1,
9338c2ecf20Sopenharmony_ci};
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixer_reverb_mode_control =
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9388c2ecf20Sopenharmony_ci	.name = "Reverb Mode",
9398c2ecf20Sopenharmony_ci	.info = mixer_chorus_reverb_info,
9408c2ecf20Sopenharmony_ci	.get = mixer_chorus_reverb_get,
9418c2ecf20Sopenharmony_ci	.put = mixer_chorus_reverb_put,
9428c2ecf20Sopenharmony_ci	.private_value = 0,
9438c2ecf20Sopenharmony_ci};
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci/*
9468c2ecf20Sopenharmony_ci * FM OPL3 chorus/reverb depth
9478c2ecf20Sopenharmony_ci */
9488c2ecf20Sopenharmony_cistatic int mixer_fm_depth_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
9518c2ecf20Sopenharmony_ci	uinfo->count = 1;
9528c2ecf20Sopenharmony_ci	uinfo->value.integer.min = 0;
9538c2ecf20Sopenharmony_ci	uinfo->value.integer.max = 255;
9548c2ecf20Sopenharmony_ci	return 0;
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
9628c2ecf20Sopenharmony_ci	return 0;
9638c2ecf20Sopenharmony_ci}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
9688c2ecf20Sopenharmony_ci	unsigned long flags;
9698c2ecf20Sopenharmony_ci	int change;
9708c2ecf20Sopenharmony_ci	unsigned short val1;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	val1 = ucontrol->value.integer.value[0] % 256;
9738c2ecf20Sopenharmony_ci	spin_lock_irqsave(&emu->control_lock, flags);
9748c2ecf20Sopenharmony_ci	if (kcontrol->private_value) {
9758c2ecf20Sopenharmony_ci		change = val1 != emu->fm_chorus_depth;
9768c2ecf20Sopenharmony_ci		emu->fm_chorus_depth = val1;
9778c2ecf20Sopenharmony_ci	} else {
9788c2ecf20Sopenharmony_ci		change = val1 != emu->fm_reverb_depth;
9798c2ecf20Sopenharmony_ci		emu->fm_reverb_depth = val1;
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&emu->control_lock, flags);
9828c2ecf20Sopenharmony_ci	if (change)
9838c2ecf20Sopenharmony_ci		snd_emu8000_init_fm(emu);
9848c2ecf20Sopenharmony_ci	return change;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixer_fm_chorus_depth_control =
9888c2ecf20Sopenharmony_ci{
9898c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
9908c2ecf20Sopenharmony_ci	.name = "FM Chorus Depth",
9918c2ecf20Sopenharmony_ci	.info = mixer_fm_depth_info,
9928c2ecf20Sopenharmony_ci	.get = mixer_fm_depth_get,
9938c2ecf20Sopenharmony_ci	.put = mixer_fm_depth_put,
9948c2ecf20Sopenharmony_ci	.private_value = 1,
9958c2ecf20Sopenharmony_ci};
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new mixer_fm_reverb_depth_control =
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
10008c2ecf20Sopenharmony_ci	.name = "FM Reverb Depth",
10018c2ecf20Sopenharmony_ci	.info = mixer_fm_depth_info,
10028c2ecf20Sopenharmony_ci	.get = mixer_fm_depth_get,
10038c2ecf20Sopenharmony_ci	.put = mixer_fm_depth_put,
10048c2ecf20Sopenharmony_ci	.private_value = 0,
10058c2ecf20Sopenharmony_ci};
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
10098c2ecf20Sopenharmony_ci	&mixer_bass_control,
10108c2ecf20Sopenharmony_ci	&mixer_treble_control,
10118c2ecf20Sopenharmony_ci	&mixer_chorus_mode_control,
10128c2ecf20Sopenharmony_ci	&mixer_reverb_mode_control,
10138c2ecf20Sopenharmony_ci	&mixer_fm_chorus_depth_control,
10148c2ecf20Sopenharmony_ci	&mixer_fm_reverb_depth_control,
10158c2ecf20Sopenharmony_ci};
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci/*
10188c2ecf20Sopenharmony_ci * create and attach mixer elements for WaveTable treble/bass controls
10198c2ecf20Sopenharmony_ci */
10208c2ecf20Sopenharmony_cistatic int
10218c2ecf20Sopenharmony_cisnd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	int i, err = 0;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	if (snd_BUG_ON(!emu || !card))
10268c2ecf20Sopenharmony_ci		return -EINVAL;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	spin_lock_init(&emu->control_lock);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	memset(emu->controls, 0, sizeof(emu->controls));
10318c2ecf20Sopenharmony_ci	for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
10328c2ecf20Sopenharmony_ci		if ((err = snd_ctl_add(card, emu->controls[i] = snd_ctl_new1(mixer_defs[i], emu))) < 0) {
10338c2ecf20Sopenharmony_ci			emu->controls[i] = NULL;
10348c2ecf20Sopenharmony_ci			goto __error;
10358c2ecf20Sopenharmony_ci		}
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci	return 0;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci__error:
10408c2ecf20Sopenharmony_ci	for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
10418c2ecf20Sopenharmony_ci		down_write(&card->controls_rwsem);
10428c2ecf20Sopenharmony_ci		if (emu->controls[i])
10438c2ecf20Sopenharmony_ci			snd_ctl_remove(card, emu->controls[i]);
10448c2ecf20Sopenharmony_ci		up_write(&card->controls_rwsem);
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci	return err;
10478c2ecf20Sopenharmony_ci}
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci/*
10518c2ecf20Sopenharmony_ci * free resources
10528c2ecf20Sopenharmony_ci */
10538c2ecf20Sopenharmony_cistatic int snd_emu8000_free(struct snd_emu8000 *hw)
10548c2ecf20Sopenharmony_ci{
10558c2ecf20Sopenharmony_ci	release_and_free_resource(hw->res_port1);
10568c2ecf20Sopenharmony_ci	release_and_free_resource(hw->res_port2);
10578c2ecf20Sopenharmony_ci	release_and_free_resource(hw->res_port3);
10588c2ecf20Sopenharmony_ci	kfree(hw);
10598c2ecf20Sopenharmony_ci	return 0;
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci/*
10638c2ecf20Sopenharmony_ci */
10648c2ecf20Sopenharmony_cistatic int snd_emu8000_dev_free(struct snd_device *device)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	struct snd_emu8000 *hw = device->device_data;
10678c2ecf20Sopenharmony_ci	return snd_emu8000_free(hw);
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci/*
10718c2ecf20Sopenharmony_ci * initialize and register emu8000 synth device.
10728c2ecf20Sopenharmony_ci */
10738c2ecf20Sopenharmony_ciint
10748c2ecf20Sopenharmony_cisnd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
10758c2ecf20Sopenharmony_ci		struct snd_seq_device **awe_ret)
10768c2ecf20Sopenharmony_ci{
10778c2ecf20Sopenharmony_ci	struct snd_seq_device *awe;
10788c2ecf20Sopenharmony_ci	struct snd_emu8000 *hw;
10798c2ecf20Sopenharmony_ci	int err;
10808c2ecf20Sopenharmony_ci	static const struct snd_device_ops ops = {
10818c2ecf20Sopenharmony_ci		.dev_free = snd_emu8000_dev_free,
10828c2ecf20Sopenharmony_ci	};
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	if (awe_ret)
10858c2ecf20Sopenharmony_ci		*awe_ret = NULL;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	if (seq_ports <= 0)
10888c2ecf20Sopenharmony_ci		return 0;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	hw = kzalloc(sizeof(*hw), GFP_KERNEL);
10918c2ecf20Sopenharmony_ci	if (hw == NULL)
10928c2ecf20Sopenharmony_ci		return -ENOMEM;
10938c2ecf20Sopenharmony_ci	spin_lock_init(&hw->reg_lock);
10948c2ecf20Sopenharmony_ci	hw->index = index;
10958c2ecf20Sopenharmony_ci	hw->port1 = port;
10968c2ecf20Sopenharmony_ci	hw->port2 = port + 0x400;
10978c2ecf20Sopenharmony_ci	hw->port3 = port + 0x800;
10988c2ecf20Sopenharmony_ci	if (!(hw->res_port1 = request_region(hw->port1, 4, "Emu8000-1")) ||
10998c2ecf20Sopenharmony_ci	    !(hw->res_port2 = request_region(hw->port2, 4, "Emu8000-2")) ||
11008c2ecf20Sopenharmony_ci	    !(hw->res_port3 = request_region(hw->port3, 4, "Emu8000-3"))) {
11018c2ecf20Sopenharmony_ci		snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
11028c2ecf20Sopenharmony_ci		snd_emu8000_free(hw);
11038c2ecf20Sopenharmony_ci		return -EBUSY;
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci	hw->mem_size = 0;
11068c2ecf20Sopenharmony_ci	hw->card = card;
11078c2ecf20Sopenharmony_ci	hw->seq_ports = seq_ports;
11088c2ecf20Sopenharmony_ci	hw->bass_level = 5;
11098c2ecf20Sopenharmony_ci	hw->treble_level = 9;
11108c2ecf20Sopenharmony_ci	hw->chorus_mode = 2;
11118c2ecf20Sopenharmony_ci	hw->reverb_mode = 4;
11128c2ecf20Sopenharmony_ci	hw->fm_chorus_depth = 0;
11138c2ecf20Sopenharmony_ci	hw->fm_reverb_depth = 0;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	if (snd_emu8000_detect(hw) < 0) {
11168c2ecf20Sopenharmony_ci		snd_emu8000_free(hw);
11178c2ecf20Sopenharmony_ci		return -ENODEV;
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	snd_emu8000_init_hw(hw);
11218c2ecf20Sopenharmony_ci	if ((err = snd_emu8000_create_mixer(card, hw)) < 0) {
11228c2ecf20Sopenharmony_ci		snd_emu8000_free(hw);
11238c2ecf20Sopenharmony_ci		return err;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	if ((err = snd_device_new(card, SNDRV_DEV_CODEC, hw, &ops)) < 0) {
11278c2ecf20Sopenharmony_ci		snd_emu8000_free(hw);
11288c2ecf20Sopenharmony_ci		return err;
11298c2ecf20Sopenharmony_ci	}
11308c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SEQUENCER)
11318c2ecf20Sopenharmony_ci	if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
11328c2ecf20Sopenharmony_ci			       sizeof(struct snd_emu8000*), &awe) >= 0) {
11338c2ecf20Sopenharmony_ci		strcpy(awe->name, "EMU-8000");
11348c2ecf20Sopenharmony_ci		*(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci#else
11378c2ecf20Sopenharmony_ci	awe = NULL;
11388c2ecf20Sopenharmony_ci#endif
11398c2ecf20Sopenharmony_ci	if (awe_ret)
11408c2ecf20Sopenharmony_ci		*awe_ret = awe;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	return 0;
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci/*
11478c2ecf20Sopenharmony_ci * exported stuff
11488c2ecf20Sopenharmony_ci */
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_poke);
11518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_peek);
11528c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_poke_dw);
11538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_peek_dw);
11548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_dma_chan);
11558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_init_fm);
11568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
11578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
11588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
11598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
11608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_emu8000_update_equalizer);
1161