cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

emu8000.c (35460B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      4 *     and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk>
      5 *  Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de>
      6 *
      7 *  Routines for control of EMU8000 chip
      8 */
      9
     10#include <linux/wait.h>
     11#include <linux/sched/signal.h>
     12#include <linux/slab.h>
     13#include <linux/ioport.h>
     14#include <linux/export.h>
     15#include <linux/delay.h>
     16#include <linux/io.h>
     17#include <sound/core.h>
     18#include <sound/emu8000.h>
     19#include <sound/emu8000_reg.h>
     20#include <linux/uaccess.h>
     21#include <linux/init.h>
     22#include <sound/control.h>
     23#include <sound/initval.h>
     24
     25/*
     26 * emu8000 register controls
     27 */
     28
     29/*
     30 * The following routines read and write registers on the emu8000.  They
     31 * should always be called via the EMU8000*READ/WRITE macros and never
     32 * directly.  The macros handle the port number and command word.
     33 */
     34/* Write a word */
     35void snd_emu8000_poke(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
     36{
     37	unsigned long flags;
     38	spin_lock_irqsave(&emu->reg_lock, flags);
     39	if (reg != emu->last_reg) {
     40		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
     41		emu->last_reg = reg;
     42	}
     43	outw((unsigned short)val, port); /* Send data */
     44	spin_unlock_irqrestore(&emu->reg_lock, flags);
     45}
     46
     47/* Read a word */
     48unsigned short snd_emu8000_peek(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
     49{
     50	unsigned short res;
     51	unsigned long flags;
     52	spin_lock_irqsave(&emu->reg_lock, flags);
     53	if (reg != emu->last_reg) {
     54		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
     55		emu->last_reg = reg;
     56	}
     57	res = inw(port);	/* Read data */
     58	spin_unlock_irqrestore(&emu->reg_lock, flags);
     59	return res;
     60}
     61
     62/* Write a double word */
     63void snd_emu8000_poke_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg, unsigned int val)
     64{
     65	unsigned long flags;
     66	spin_lock_irqsave(&emu->reg_lock, flags);
     67	if (reg != emu->last_reg) {
     68		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
     69		emu->last_reg = reg;
     70	}
     71	outw((unsigned short)val, port); /* Send low word of data */
     72	outw((unsigned short)(val>>16), port+2); /* Send high word of data */
     73	spin_unlock_irqrestore(&emu->reg_lock, flags);
     74}
     75
     76/* Read a double word */
     77unsigned int snd_emu8000_peek_dw(struct snd_emu8000 *emu, unsigned int port, unsigned int reg)
     78{
     79	unsigned short low;
     80	unsigned int res;
     81	unsigned long flags;
     82	spin_lock_irqsave(&emu->reg_lock, flags);
     83	if (reg != emu->last_reg) {
     84		outw((unsigned short)reg, EMU8000_PTR(emu)); /* Set register */
     85		emu->last_reg = reg;
     86	}
     87	low = inw(port);	/* Read low word of data */
     88	res = low + (inw(port+2) << 16);
     89	spin_unlock_irqrestore(&emu->reg_lock, flags);
     90	return res;
     91}
     92
     93/*
     94 * Set up / close a channel to be used for DMA.
     95 */
     96/*exported*/ void
     97snd_emu8000_dma_chan(struct snd_emu8000 *emu, int ch, int mode)
     98{
     99	unsigned right_bit = (mode & EMU8000_RAM_RIGHT) ? 0x01000000 : 0;
    100	mode &= EMU8000_RAM_MODE_MASK;
    101	if (mode == EMU8000_RAM_CLOSE) {
    102		EMU8000_CCCA_WRITE(emu, ch, 0);
    103		EMU8000_DCYSUSV_WRITE(emu, ch, 0x807F);
    104		return;
    105	}
    106	EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
    107	EMU8000_VTFT_WRITE(emu, ch, 0);
    108	EMU8000_CVCF_WRITE(emu, ch, 0);
    109	EMU8000_PTRX_WRITE(emu, ch, 0x40000000);
    110	EMU8000_CPF_WRITE(emu, ch, 0x40000000);
    111	EMU8000_PSST_WRITE(emu, ch, 0);
    112	EMU8000_CSL_WRITE(emu, ch, 0);
    113	if (mode == EMU8000_RAM_WRITE) /* DMA write */
    114		EMU8000_CCCA_WRITE(emu, ch, 0x06000000 | right_bit);
    115	else	   /* DMA read */
    116		EMU8000_CCCA_WRITE(emu, ch, 0x04000000 | right_bit);
    117}
    118
    119/*
    120 */
    121static void
    122snd_emu8000_read_wait(struct snd_emu8000 *emu)
    123{
    124	while ((EMU8000_SMALR_READ(emu) & 0x80000000) != 0) {
    125		schedule_timeout_interruptible(1);
    126		if (signal_pending(current))
    127			break;
    128	}
    129}
    130
    131/*
    132 */
    133static void
    134snd_emu8000_write_wait(struct snd_emu8000 *emu)
    135{
    136	while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
    137		schedule_timeout_interruptible(1);
    138		if (signal_pending(current))
    139			break;
    140	}
    141}
    142
    143/*
    144 * detect a card at the given port
    145 */
    146static int
    147snd_emu8000_detect(struct snd_emu8000 *emu)
    148{
    149	/* Initialise */
    150	EMU8000_HWCF1_WRITE(emu, 0x0059);
    151	EMU8000_HWCF2_WRITE(emu, 0x0020);
    152	EMU8000_HWCF3_WRITE(emu, 0x0000);
    153	/* Check for a recognisable emu8000 */
    154	/*
    155	if ((EMU8000_U1_READ(emu) & 0x000f) != 0x000c)
    156		return -ENODEV;
    157		*/
    158	if ((EMU8000_HWCF1_READ(emu) & 0x007e) != 0x0058)
    159		return -ENODEV;
    160	if ((EMU8000_HWCF2_READ(emu) & 0x0003) != 0x0003)
    161		return -ENODEV;
    162
    163	snd_printdd("EMU8000 [0x%lx]: Synth chip found\n",
    164                    emu->port1);
    165	return 0;
    166}
    167
    168
    169/*
    170 * intiailize audio channels
    171 */
    172static void
    173init_audio(struct snd_emu8000 *emu)
    174{
    175	int ch;
    176
    177	/* turn off envelope engines */
    178	for (ch = 0; ch < EMU8000_CHANNELS; ch++)
    179		EMU8000_DCYSUSV_WRITE(emu, ch, 0x80);
    180  
    181	/* reset all other parameters to zero */
    182	for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
    183		EMU8000_ENVVOL_WRITE(emu, ch, 0);
    184		EMU8000_ENVVAL_WRITE(emu, ch, 0);
    185		EMU8000_DCYSUS_WRITE(emu, ch, 0);
    186		EMU8000_ATKHLDV_WRITE(emu, ch, 0);
    187		EMU8000_LFO1VAL_WRITE(emu, ch, 0);
    188		EMU8000_ATKHLD_WRITE(emu, ch, 0);
    189		EMU8000_LFO2VAL_WRITE(emu, ch, 0);
    190		EMU8000_IP_WRITE(emu, ch, 0);
    191		EMU8000_IFATN_WRITE(emu, ch, 0);
    192		EMU8000_PEFE_WRITE(emu, ch, 0);
    193		EMU8000_FMMOD_WRITE(emu, ch, 0);
    194		EMU8000_TREMFRQ_WRITE(emu, ch, 0);
    195		EMU8000_FM2FRQ2_WRITE(emu, ch, 0);
    196		EMU8000_PTRX_WRITE(emu, ch, 0);
    197		EMU8000_VTFT_WRITE(emu, ch, 0);
    198		EMU8000_PSST_WRITE(emu, ch, 0);
    199		EMU8000_CSL_WRITE(emu, ch, 0);
    200		EMU8000_CCCA_WRITE(emu, ch, 0);
    201	}
    202
    203	for (ch = 0; ch < EMU8000_CHANNELS; ch++) {
    204		EMU8000_CPF_WRITE(emu, ch, 0);
    205		EMU8000_CVCF_WRITE(emu, ch, 0);
    206	}
    207}
    208
    209
    210/*
    211 * initialize DMA address
    212 */
    213static void
    214init_dma(struct snd_emu8000 *emu)
    215{
    216	EMU8000_SMALR_WRITE(emu, 0);
    217	EMU8000_SMARR_WRITE(emu, 0);
    218	EMU8000_SMALW_WRITE(emu, 0);
    219	EMU8000_SMARW_WRITE(emu, 0);
    220}
    221
    222/*
    223 * initialization arrays; from ADIP
    224 */
    225static const unsigned short init1[128] = {
    226	0x03ff, 0x0030,  0x07ff, 0x0130, 0x0bff, 0x0230,  0x0fff, 0x0330,
    227	0x13ff, 0x0430,  0x17ff, 0x0530, 0x1bff, 0x0630,  0x1fff, 0x0730,
    228	0x23ff, 0x0830,  0x27ff, 0x0930, 0x2bff, 0x0a30,  0x2fff, 0x0b30,
    229	0x33ff, 0x0c30,  0x37ff, 0x0d30, 0x3bff, 0x0e30,  0x3fff, 0x0f30,
    230
    231	0x43ff, 0x0030,  0x47ff, 0x0130, 0x4bff, 0x0230,  0x4fff, 0x0330,
    232	0x53ff, 0x0430,  0x57ff, 0x0530, 0x5bff, 0x0630,  0x5fff, 0x0730,
    233	0x63ff, 0x0830,  0x67ff, 0x0930, 0x6bff, 0x0a30,  0x6fff, 0x0b30,
    234	0x73ff, 0x0c30,  0x77ff, 0x0d30, 0x7bff, 0x0e30,  0x7fff, 0x0f30,
    235
    236	0x83ff, 0x0030,  0x87ff, 0x0130, 0x8bff, 0x0230,  0x8fff, 0x0330,
    237	0x93ff, 0x0430,  0x97ff, 0x0530, 0x9bff, 0x0630,  0x9fff, 0x0730,
    238	0xa3ff, 0x0830,  0xa7ff, 0x0930, 0xabff, 0x0a30,  0xafff, 0x0b30,
    239	0xb3ff, 0x0c30,  0xb7ff, 0x0d30, 0xbbff, 0x0e30,  0xbfff, 0x0f30,
    240
    241	0xc3ff, 0x0030,  0xc7ff, 0x0130, 0xcbff, 0x0230,  0xcfff, 0x0330,
    242	0xd3ff, 0x0430,  0xd7ff, 0x0530, 0xdbff, 0x0630,  0xdfff, 0x0730,
    243	0xe3ff, 0x0830,  0xe7ff, 0x0930, 0xebff, 0x0a30,  0xefff, 0x0b30,
    244	0xf3ff, 0x0c30,  0xf7ff, 0x0d30, 0xfbff, 0x0e30,  0xffff, 0x0f30,
    245};
    246
    247static const unsigned short init2[128] = {
    248	0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
    249	0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
    250	0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
    251	0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
    252
    253	0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
    254	0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
    255	0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
    256	0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
    257
    258	0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
    259	0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
    260	0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
    261	0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
    262
    263	0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
    264	0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
    265	0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
    266	0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
    267};
    268
    269static const unsigned short init3[128] = {
    270	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
    271	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
    272	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
    273	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
    274
    275	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
    276	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
    277	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
    278	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
    279
    280	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
    281	0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
    282	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
    283	0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
    284
    285	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
    286	0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
    287	0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
    288	0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
    289};
    290
    291static const unsigned short init4[128] = {
    292	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
    293	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
    294	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
    295	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
    296
    297	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
    298	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
    299	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
    300	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
    301
    302	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
    303	0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
    304	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
    305	0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
    306
    307	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
    308	0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
    309	0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
    310	0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
    311};
    312
    313/* send an initialization array
    314 * Taken from the oss driver, not obvious from the doc how this
    315 * is meant to work
    316 */
    317static void
    318send_array(struct snd_emu8000 *emu, const unsigned short *data, int size)
    319{
    320	int i;
    321	const unsigned short *p;
    322
    323	p = data;
    324	for (i = 0; i < size; i++, p++)
    325		EMU8000_INIT1_WRITE(emu, i, *p);
    326	for (i = 0; i < size; i++, p++)
    327		EMU8000_INIT2_WRITE(emu, i, *p);
    328	for (i = 0; i < size; i++, p++)
    329		EMU8000_INIT3_WRITE(emu, i, *p);
    330	for (i = 0; i < size; i++, p++)
    331		EMU8000_INIT4_WRITE(emu, i, *p);
    332}
    333
    334
    335/*
    336 * Send initialization arrays to start up, this just follows the
    337 * initialisation sequence in the adip.
    338 */
    339static void
    340init_arrays(struct snd_emu8000 *emu)
    341{
    342	send_array(emu, init1, ARRAY_SIZE(init1)/4);
    343
    344	msleep((1024 * 1000) / 44100); /* wait for 1024 clocks */
    345	send_array(emu, init2, ARRAY_SIZE(init2)/4);
    346	send_array(emu, init3, ARRAY_SIZE(init3)/4);
    347
    348	EMU8000_HWCF4_WRITE(emu, 0);
    349	EMU8000_HWCF5_WRITE(emu, 0x83);
    350	EMU8000_HWCF6_WRITE(emu, 0x8000);
    351
    352	send_array(emu, init4, ARRAY_SIZE(init4)/4);
    353}
    354
    355
    356#define UNIQUE_ID1	0xa5b9
    357#define UNIQUE_ID2	0x9d53
    358
    359/*
    360 * Size the onboard memory.
    361 * This is written so as not to need arbitrary delays after the write. It
    362 * seems that the only way to do this is to use the one channel and keep
    363 * reallocating between read and write.
    364 */
    365static void
    366size_dram(struct snd_emu8000 *emu)
    367{
    368	int i, size;
    369
    370	if (emu->dram_checked)
    371		return;
    372
    373	size = 0;
    374
    375	/* write out a magic number */
    376	snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);
    377	snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_READ);
    378	EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET);
    379	EMU8000_SMLD_WRITE(emu, UNIQUE_ID1);
    380	snd_emu8000_init_fm(emu); /* This must really be here and not 2 lines back even */
    381	snd_emu8000_write_wait(emu);
    382
    383	/*
    384	 * Detect first 512 KiB.  If a write succeeds at the beginning of a
    385	 * 512 KiB page we assume that the whole page is there.
    386	 */
    387	EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
    388	EMU8000_SMLD_READ(emu); /* discard stale data  */
    389	if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
    390		goto skip_detect;   /* No RAM */
    391	snd_emu8000_read_wait(emu);
    392
    393	for (size = 512 * 1024; size < EMU8000_MAX_DRAM; size += 512 * 1024) {
    394
    395		/* Write a unique data on the test address.
    396		 * if the address is out of range, the data is written on
    397		 * 0x200000(=EMU8000_DRAM_OFFSET).  Then the id word is
    398		 * changed by this data.
    399		 */
    400		/*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_WRITE);*/
    401		EMU8000_SMALW_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
    402		EMU8000_SMLD_WRITE(emu, UNIQUE_ID2);
    403		snd_emu8000_write_wait(emu);
    404
    405		/*
    406		 * read the data on the just written DRAM address
    407		 * if not the same then we have reached the end of ram.
    408		 */
    409		/*snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_READ);*/
    410		EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET + (size>>1));
    411		/*snd_emu8000_read_wait(emu);*/
    412		EMU8000_SMLD_READ(emu); /* discard stale data  */
    413		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2)
    414			break; /* no memory at this address */
    415		snd_emu8000_read_wait(emu);
    416
    417		/*
    418		 * If it is the same it could be that the address just
    419		 * wraps back to the beginning; so check to see if the
    420		 * initial value has been overwritten.
    421		 */
    422		EMU8000_SMALR_WRITE(emu, EMU8000_DRAM_OFFSET);
    423		EMU8000_SMLD_READ(emu); /* discard stale data  */
    424		if (EMU8000_SMLD_READ(emu) != UNIQUE_ID1)
    425			break; /* we must have wrapped around */
    426		snd_emu8000_read_wait(emu);
    427
    428		/* Otherwise, it's valid memory. */
    429	}
    430
    431skip_detect:
    432	/* wait until FULL bit in SMAxW register is false */
    433	for (i = 0; i < 10000; i++) {
    434		if ((EMU8000_SMALW_READ(emu) & 0x80000000) == 0)
    435			break;
    436		schedule_timeout_interruptible(1);
    437		if (signal_pending(current))
    438			break;
    439	}
    440	snd_emu8000_dma_chan(emu, 0, EMU8000_RAM_CLOSE);
    441	snd_emu8000_dma_chan(emu, 1, EMU8000_RAM_CLOSE);
    442
    443	pr_info("EMU8000 [0x%lx]: %d KiB on-board DRAM detected\n",
    444		    emu->port1, size/1024);
    445
    446	emu->mem_size = size;
    447	emu->dram_checked = 1;
    448}
    449
    450
    451/*
    452 * Initiailise the FM section.  You have to do this to use sample RAM
    453 * and therefore lose 2 voices.
    454 */
    455/*exported*/ void
    456snd_emu8000_init_fm(struct snd_emu8000 *emu)
    457{
    458	unsigned long flags;
    459
    460	/* Initialize the last two channels for DRAM refresh and producing
    461	   the reverb and chorus effects for Yamaha OPL-3 synthesizer */
    462
    463	/* 31: FM left channel, 0xffffe0-0xffffe8 */
    464	EMU8000_DCYSUSV_WRITE(emu, 30, 0x80);
    465	EMU8000_PSST_WRITE(emu, 30, 0xFFFFFFE0); /* full left */
    466	EMU8000_CSL_WRITE(emu, 30, 0x00FFFFE8 | (emu->fm_chorus_depth << 24));
    467	EMU8000_PTRX_WRITE(emu, 30, (emu->fm_reverb_depth << 8));
    468	EMU8000_CPF_WRITE(emu, 30, 0);
    469	EMU8000_CCCA_WRITE(emu, 30, 0x00FFFFE3);
    470
    471	/* 32: FM right channel, 0xfffff0-0xfffff8 */
    472	EMU8000_DCYSUSV_WRITE(emu, 31, 0x80);
    473	EMU8000_PSST_WRITE(emu, 31, 0x00FFFFF0); /* full right */
    474	EMU8000_CSL_WRITE(emu, 31, 0x00FFFFF8 | (emu->fm_chorus_depth << 24));
    475	EMU8000_PTRX_WRITE(emu, 31, (emu->fm_reverb_depth << 8));
    476	EMU8000_CPF_WRITE(emu, 31, 0x8000);
    477	EMU8000_CCCA_WRITE(emu, 31, 0x00FFFFF3);
    478
    479	snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0);
    480
    481	spin_lock_irqsave(&emu->reg_lock, flags);
    482	while (!(inw(EMU8000_PTR(emu)) & 0x1000))
    483		;
    484	while ((inw(EMU8000_PTR(emu)) & 0x1000))
    485		;
    486	spin_unlock_irqrestore(&emu->reg_lock, flags);
    487	snd_emu8000_poke((emu), EMU8000_DATA0(emu), EMU8000_CMD(1, (30)), 0x4828);
    488	/* this is really odd part.. */
    489	outb(0x3C, EMU8000_PTR(emu));
    490	outb(0, EMU8000_DATA1(emu));
    491
    492	/* skew volume & cutoff */
    493	EMU8000_VTFT_WRITE(emu, 30, 0x8000FFFF);
    494	EMU8000_VTFT_WRITE(emu, 31, 0x8000FFFF);
    495}
    496
    497
    498/*
    499 * The main initialization routine.
    500 */
    501static void
    502snd_emu8000_init_hw(struct snd_emu8000 *emu)
    503{
    504	int i;
    505
    506	emu->last_reg = 0xffff; /* reset the last register index */
    507
    508	/* initialize hardware configuration */
    509	EMU8000_HWCF1_WRITE(emu, 0x0059);
    510	EMU8000_HWCF2_WRITE(emu, 0x0020);
    511
    512	/* disable audio; this seems to reduce a clicking noise a bit.. */
    513	EMU8000_HWCF3_WRITE(emu, 0);
    514
    515	/* initialize audio channels */
    516	init_audio(emu);
    517
    518	/* initialize DMA */
    519	init_dma(emu);
    520
    521	/* initialize init arrays */
    522	init_arrays(emu);
    523
    524	/*
    525	 * Initialize the FM section of the AWE32, this is needed
    526	 * for DRAM refresh as well
    527	 */
    528	snd_emu8000_init_fm(emu);
    529
    530	/* terminate all voices */
    531	for (i = 0; i < EMU8000_DRAM_VOICES; i++)
    532		EMU8000_DCYSUSV_WRITE(emu, 0, 0x807F);
    533	
    534	/* check DRAM memory size */
    535	size_dram(emu);
    536
    537	/* enable audio */
    538	EMU8000_HWCF3_WRITE(emu, 0x4);
    539
    540	/* set equzlier, chorus and reverb modes */
    541	snd_emu8000_update_equalizer(emu);
    542	snd_emu8000_update_chorus_mode(emu);
    543	snd_emu8000_update_reverb_mode(emu);
    544}
    545
    546
    547/*----------------------------------------------------------------
    548 * Bass/Treble Equalizer
    549 *----------------------------------------------------------------*/
    550
    551static const unsigned short bass_parm[12][3] = {
    552	{0xD26A, 0xD36A, 0x0000}, /* -12 dB */
    553	{0xD25B, 0xD35B, 0x0000}, /*  -8 */
    554	{0xD24C, 0xD34C, 0x0000}, /*  -6 */
    555	{0xD23D, 0xD33D, 0x0000}, /*  -4 */
    556	{0xD21F, 0xD31F, 0x0000}, /*  -2 */
    557	{0xC208, 0xC308, 0x0001}, /*   0 (HW default) */
    558	{0xC219, 0xC319, 0x0001}, /*  +2 */
    559	{0xC22A, 0xC32A, 0x0001}, /*  +4 */
    560	{0xC24C, 0xC34C, 0x0001}, /*  +6 */
    561	{0xC26E, 0xC36E, 0x0001}, /*  +8 */
    562	{0xC248, 0xC384, 0x0002}, /* +10 */
    563	{0xC26A, 0xC36A, 0x0002}, /* +12 dB */
    564};
    565
    566static const unsigned short treble_parm[12][9] = {
    567	{0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
    568	{0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
    569	{0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
    570	{0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
    571	{0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
    572	{0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
    573	{0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
    574	{0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
    575	{0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
    576	{0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
    577	{0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
    578	{0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}  /* +12 dB */
    579};
    580
    581
    582/*
    583 * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
    584 */
    585/*exported*/ void
    586snd_emu8000_update_equalizer(struct snd_emu8000 *emu)
    587{
    588	unsigned short w;
    589	int bass = emu->bass_level;
    590	int treble = emu->treble_level;
    591
    592	if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
    593		return;
    594	EMU8000_INIT4_WRITE(emu, 0x01, bass_parm[bass][0]);
    595	EMU8000_INIT4_WRITE(emu, 0x11, bass_parm[bass][1]);
    596	EMU8000_INIT3_WRITE(emu, 0x11, treble_parm[treble][0]);
    597	EMU8000_INIT3_WRITE(emu, 0x13, treble_parm[treble][1]);
    598	EMU8000_INIT3_WRITE(emu, 0x1b, treble_parm[treble][2]);
    599	EMU8000_INIT4_WRITE(emu, 0x07, treble_parm[treble][3]);
    600	EMU8000_INIT4_WRITE(emu, 0x0b, treble_parm[treble][4]);
    601	EMU8000_INIT4_WRITE(emu, 0x0d, treble_parm[treble][5]);
    602	EMU8000_INIT4_WRITE(emu, 0x17, treble_parm[treble][6]);
    603	EMU8000_INIT4_WRITE(emu, 0x19, treble_parm[treble][7]);
    604	w = bass_parm[bass][2] + treble_parm[treble][8];
    605	EMU8000_INIT4_WRITE(emu, 0x15, (unsigned short)(w + 0x0262));
    606	EMU8000_INIT4_WRITE(emu, 0x1d, (unsigned short)(w + 0x8362));
    607}
    608
    609
    610/*----------------------------------------------------------------
    611 * Chorus mode control
    612 *----------------------------------------------------------------*/
    613
    614/*
    615 * chorus mode parameters
    616 */
    617#define SNDRV_EMU8000_CHORUS_1		0
    618#define	SNDRV_EMU8000_CHORUS_2		1
    619#define	SNDRV_EMU8000_CHORUS_3		2
    620#define	SNDRV_EMU8000_CHORUS_4		3
    621#define	SNDRV_EMU8000_CHORUS_FEEDBACK	4
    622#define	SNDRV_EMU8000_CHORUS_FLANGER	5
    623#define	SNDRV_EMU8000_CHORUS_SHORTDELAY	6
    624#define	SNDRV_EMU8000_CHORUS_SHORTDELAY2	7
    625#define SNDRV_EMU8000_CHORUS_PREDEFINED	8
    626/* user can define chorus modes up to 32 */
    627#define SNDRV_EMU8000_CHORUS_NUMBERS	32
    628
    629struct soundfont_chorus_fx {
    630	unsigned short feedback;	/* feedback level (0xE600-0xE6FF) */
    631	unsigned short delay_offset;	/* delay (0-0x0DA3) [1/44100 sec] */
    632	unsigned short lfo_depth;	/* LFO depth (0xBC00-0xBCFF) */
    633	unsigned int delay;	/* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
    634	unsigned int lfo_freq;		/* LFO freq LFO freq (0-0xFFFFFFFF) */
    635};
    636
    637/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
    638static char chorus_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
    639static struct soundfont_chorus_fx chorus_parm[SNDRV_EMU8000_CHORUS_NUMBERS] = {
    640	{0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
    641	{0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
    642	{0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
    643	{0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
    644	{0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
    645	{0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
    646	{0xE600, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay */
    647	{0xE6C0, 0x0B06, 0xBC00, 0x0006E000, 0x00000083}, /* short delay + feedback */
    648};
    649
    650/*exported*/ int
    651snd_emu8000_load_chorus_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
    652{
    653	struct soundfont_chorus_fx rec;
    654	if (mode < SNDRV_EMU8000_CHORUS_PREDEFINED || mode >= SNDRV_EMU8000_CHORUS_NUMBERS) {
    655		snd_printk(KERN_WARNING "invalid chorus mode %d for uploading\n", mode);
    656		return -EINVAL;
    657	}
    658	if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
    659		return -EFAULT;
    660	chorus_parm[mode] = rec;
    661	chorus_defined[mode] = 1;
    662	return 0;
    663}
    664
    665/*exported*/ void
    666snd_emu8000_update_chorus_mode(struct snd_emu8000 *emu)
    667{
    668	int effect = emu->chorus_mode;
    669	if (effect < 0 || effect >= SNDRV_EMU8000_CHORUS_NUMBERS ||
    670	    (effect >= SNDRV_EMU8000_CHORUS_PREDEFINED && !chorus_defined[effect]))
    671		return;
    672	EMU8000_INIT3_WRITE(emu, 0x09, chorus_parm[effect].feedback);
    673	EMU8000_INIT3_WRITE(emu, 0x0c, chorus_parm[effect].delay_offset);
    674	EMU8000_INIT4_WRITE(emu, 0x03, chorus_parm[effect].lfo_depth);
    675	EMU8000_HWCF4_WRITE(emu, chorus_parm[effect].delay);
    676	EMU8000_HWCF5_WRITE(emu, chorus_parm[effect].lfo_freq);
    677	EMU8000_HWCF6_WRITE(emu, 0x8000);
    678	EMU8000_HWCF7_WRITE(emu, 0x0000);
    679}
    680
    681/*----------------------------------------------------------------
    682 * Reverb mode control
    683 *----------------------------------------------------------------*/
    684
    685/*
    686 * reverb mode parameters
    687 */
    688#define	SNDRV_EMU8000_REVERB_ROOM1	0
    689#define SNDRV_EMU8000_REVERB_ROOM2	1
    690#define	SNDRV_EMU8000_REVERB_ROOM3	2
    691#define	SNDRV_EMU8000_REVERB_HALL1	3
    692#define	SNDRV_EMU8000_REVERB_HALL2	4
    693#define	SNDRV_EMU8000_REVERB_PLATE	5
    694#define	SNDRV_EMU8000_REVERB_DELAY	6
    695#define	SNDRV_EMU8000_REVERB_PANNINGDELAY 7
    696#define SNDRV_EMU8000_REVERB_PREDEFINED	8
    697/* user can define reverb modes up to 32 */
    698#define SNDRV_EMU8000_REVERB_NUMBERS	32
    699
    700struct soundfont_reverb_fx {
    701	unsigned short parms[28];
    702};
    703
    704/* reverb mode settings; write the following 28 data of 16 bit length
    705 *   on the corresponding ports in the reverb_cmds array
    706 */
    707static char reverb_defined[SNDRV_EMU8000_CHORUS_NUMBERS];
    708static struct soundfont_reverb_fx reverb_parm[SNDRV_EMU8000_REVERB_NUMBERS] = {
    709{{  /* room 1 */
    710	0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
    711	0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
    712	0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
    713	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
    714}},
    715{{  /* room 2 */
    716	0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
    717	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
    718	0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
    719	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
    720}},
    721{{  /* room 3 */
    722	0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
    723	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
    724	0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
    725	0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
    726}},
    727{{  /* hall 1 */
    728	0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
    729	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
    730	0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
    731	0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
    732}},
    733{{  /* hall 2 */
    734	0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
    735	0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
    736	0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
    737	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
    738}},
    739{{  /* plate */
    740	0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
    741	0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
    742	0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
    743	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
    744}},
    745{{  /* delay */
    746	0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
    747	0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
    748	0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
    749	0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
    750}},
    751{{  /* panning delay */
    752	0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
    753	0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
    754	0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
    755	0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
    756}},
    757};
    758
    759enum { DATA1, DATA2 };
    760#define AWE_INIT1(c)	EMU8000_CMD(2,c), DATA1
    761#define AWE_INIT2(c)	EMU8000_CMD(2,c), DATA2
    762#define AWE_INIT3(c)	EMU8000_CMD(3,c), DATA1
    763#define AWE_INIT4(c)	EMU8000_CMD(3,c), DATA2
    764
    765static struct reverb_cmd_pair {
    766	unsigned short cmd, port;
    767} reverb_cmds[28] = {
    768  {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
    769  {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
    770  {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
    771  {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
    772  {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
    773  {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
    774  {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
    775};
    776
    777/*exported*/ int
    778snd_emu8000_load_reverb_fx(struct snd_emu8000 *emu, int mode, const void __user *buf, long len)
    779{
    780	struct soundfont_reverb_fx rec;
    781
    782	if (mode < SNDRV_EMU8000_REVERB_PREDEFINED || mode >= SNDRV_EMU8000_REVERB_NUMBERS) {
    783		snd_printk(KERN_WARNING "invalid reverb mode %d for uploading\n", mode);
    784		return -EINVAL;
    785	}
    786	if (len < (long)sizeof(rec) || copy_from_user(&rec, buf, sizeof(rec)))
    787		return -EFAULT;
    788	reverb_parm[mode] = rec;
    789	reverb_defined[mode] = 1;
    790	return 0;
    791}
    792
    793/*exported*/ void
    794snd_emu8000_update_reverb_mode(struct snd_emu8000 *emu)
    795{
    796	int effect = emu->reverb_mode;
    797	int i;
    798
    799	if (effect < 0 || effect >= SNDRV_EMU8000_REVERB_NUMBERS ||
    800	    (effect >= SNDRV_EMU8000_REVERB_PREDEFINED && !reverb_defined[effect]))
    801		return;
    802	for (i = 0; i < 28; i++) {
    803		int port;
    804		if (reverb_cmds[i].port == DATA1)
    805			port = EMU8000_DATA1(emu);
    806		else
    807			port = EMU8000_DATA2(emu);
    808		snd_emu8000_poke(emu, port, reverb_cmds[i].cmd, reverb_parm[effect].parms[i]);
    809	}
    810}
    811
    812
    813/*----------------------------------------------------------------
    814 * mixer interface
    815 *----------------------------------------------------------------*/
    816
    817/*
    818 * bass/treble
    819 */
    820static int mixer_bass_treble_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
    821{
    822	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    823	uinfo->count = 1;
    824	uinfo->value.integer.min = 0;
    825	uinfo->value.integer.max = 11;
    826	return 0;
    827}
    828
    829static int mixer_bass_treble_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    830{
    831	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
    832	
    833	ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->treble_level : emu->bass_level;
    834	return 0;
    835}
    836
    837static int mixer_bass_treble_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    838{
    839	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
    840	unsigned long flags;
    841	int change;
    842	unsigned short val1;
    843	
    844	val1 = ucontrol->value.integer.value[0] % 12;
    845	spin_lock_irqsave(&emu->control_lock, flags);
    846	if (kcontrol->private_value) {
    847		change = val1 != emu->treble_level;
    848		emu->treble_level = val1;
    849	} else {
    850		change = val1 != emu->bass_level;
    851		emu->bass_level = val1;
    852	}
    853	spin_unlock_irqrestore(&emu->control_lock, flags);
    854	snd_emu8000_update_equalizer(emu);
    855	return change;
    856}
    857
    858static const struct snd_kcontrol_new mixer_bass_control =
    859{
    860	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    861	.name = "Synth Tone Control - Bass",
    862	.info = mixer_bass_treble_info,
    863	.get = mixer_bass_treble_get,
    864	.put = mixer_bass_treble_put,
    865	.private_value = 0,
    866};
    867
    868static const struct snd_kcontrol_new mixer_treble_control =
    869{
    870	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    871	.name = "Synth Tone Control - Treble",
    872	.info = mixer_bass_treble_info,
    873	.get = mixer_bass_treble_get,
    874	.put = mixer_bass_treble_put,
    875	.private_value = 1,
    876};
    877
    878/*
    879 * chorus/reverb mode
    880 */
    881static int mixer_chorus_reverb_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
    882{
    883	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    884	uinfo->count = 1;
    885	uinfo->value.integer.min = 0;
    886	uinfo->value.integer.max = kcontrol->private_value ? (SNDRV_EMU8000_CHORUS_NUMBERS-1) : (SNDRV_EMU8000_REVERB_NUMBERS-1);
    887	return 0;
    888}
    889
    890static int mixer_chorus_reverb_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    891{
    892	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
    893	
    894	ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->chorus_mode : emu->reverb_mode;
    895	return 0;
    896}
    897
    898static int mixer_chorus_reverb_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    899{
    900	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
    901	unsigned long flags;
    902	int change;
    903	unsigned short val1;
    904	
    905	spin_lock_irqsave(&emu->control_lock, flags);
    906	if (kcontrol->private_value) {
    907		val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_CHORUS_NUMBERS;
    908		change = val1 != emu->chorus_mode;
    909		emu->chorus_mode = val1;
    910	} else {
    911		val1 = ucontrol->value.integer.value[0] % SNDRV_EMU8000_REVERB_NUMBERS;
    912		change = val1 != emu->reverb_mode;
    913		emu->reverb_mode = val1;
    914	}
    915	spin_unlock_irqrestore(&emu->control_lock, flags);
    916	if (change) {
    917		if (kcontrol->private_value)
    918			snd_emu8000_update_chorus_mode(emu);
    919		else
    920			snd_emu8000_update_reverb_mode(emu);
    921	}
    922	return change;
    923}
    924
    925static const struct snd_kcontrol_new mixer_chorus_mode_control =
    926{
    927	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    928	.name = "Chorus Mode",
    929	.info = mixer_chorus_reverb_info,
    930	.get = mixer_chorus_reverb_get,
    931	.put = mixer_chorus_reverb_put,
    932	.private_value = 1,
    933};
    934
    935static const struct snd_kcontrol_new mixer_reverb_mode_control =
    936{
    937	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    938	.name = "Reverb Mode",
    939	.info = mixer_chorus_reverb_info,
    940	.get = mixer_chorus_reverb_get,
    941	.put = mixer_chorus_reverb_put,
    942	.private_value = 0,
    943};
    944
    945/*
    946 * FM OPL3 chorus/reverb depth
    947 */
    948static int mixer_fm_depth_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
    949{
    950	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    951	uinfo->count = 1;
    952	uinfo->value.integer.min = 0;
    953	uinfo->value.integer.max = 255;
    954	return 0;
    955}
    956
    957static int mixer_fm_depth_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    958{
    959	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
    960	
    961	ucontrol->value.integer.value[0] = kcontrol->private_value ? emu->fm_chorus_depth : emu->fm_reverb_depth;
    962	return 0;
    963}
    964
    965static int mixer_fm_depth_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
    966{
    967	struct snd_emu8000 *emu = snd_kcontrol_chip(kcontrol);
    968	unsigned long flags;
    969	int change;
    970	unsigned short val1;
    971	
    972	val1 = ucontrol->value.integer.value[0] % 256;
    973	spin_lock_irqsave(&emu->control_lock, flags);
    974	if (kcontrol->private_value) {
    975		change = val1 != emu->fm_chorus_depth;
    976		emu->fm_chorus_depth = val1;
    977	} else {
    978		change = val1 != emu->fm_reverb_depth;
    979		emu->fm_reverb_depth = val1;
    980	}
    981	spin_unlock_irqrestore(&emu->control_lock, flags);
    982	if (change)
    983		snd_emu8000_init_fm(emu);
    984	return change;
    985}
    986
    987static const struct snd_kcontrol_new mixer_fm_chorus_depth_control =
    988{
    989	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    990	.name = "FM Chorus Depth",
    991	.info = mixer_fm_depth_info,
    992	.get = mixer_fm_depth_get,
    993	.put = mixer_fm_depth_put,
    994	.private_value = 1,
    995};
    996
    997static const struct snd_kcontrol_new mixer_fm_reverb_depth_control =
    998{
    999	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
   1000	.name = "FM Reverb Depth",
   1001	.info = mixer_fm_depth_info,
   1002	.get = mixer_fm_depth_get,
   1003	.put = mixer_fm_depth_put,
   1004	.private_value = 0,
   1005};
   1006
   1007
   1008static const struct snd_kcontrol_new *mixer_defs[EMU8000_NUM_CONTROLS] = {
   1009	&mixer_bass_control,
   1010	&mixer_treble_control,
   1011	&mixer_chorus_mode_control,
   1012	&mixer_reverb_mode_control,
   1013	&mixer_fm_chorus_depth_control,
   1014	&mixer_fm_reverb_depth_control,
   1015};
   1016
   1017/*
   1018 * create and attach mixer elements for WaveTable treble/bass controls
   1019 */
   1020static int
   1021snd_emu8000_create_mixer(struct snd_card *card, struct snd_emu8000 *emu)
   1022{
   1023	struct snd_kcontrol *kctl;
   1024	int i, err = 0;
   1025
   1026	if (snd_BUG_ON(!emu || !card))
   1027		return -EINVAL;
   1028
   1029	spin_lock_init(&emu->control_lock);
   1030
   1031	memset(emu->controls, 0, sizeof(emu->controls));
   1032	for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
   1033		kctl = snd_ctl_new1(mixer_defs[i], emu);
   1034		err = snd_ctl_add(card, kctl);
   1035		if (err < 0)
   1036			goto __error;
   1037		emu->controls[i] = kctl;
   1038	}
   1039	return 0;
   1040
   1041__error:
   1042	for (i = 0; i < EMU8000_NUM_CONTROLS; i++) {
   1043		down_write(&card->controls_rwsem);
   1044		if (emu->controls[i])
   1045			snd_ctl_remove(card, emu->controls[i]);
   1046		up_write(&card->controls_rwsem);
   1047	}
   1048	return err;
   1049}
   1050
   1051/*
   1052 * initialize and register emu8000 synth device.
   1053 */
   1054int
   1055snd_emu8000_new(struct snd_card *card, int index, long port, int seq_ports,
   1056		struct snd_seq_device **awe_ret)
   1057{
   1058	struct snd_seq_device *awe;
   1059	struct snd_emu8000 *hw;
   1060	int err;
   1061
   1062	if (awe_ret)
   1063		*awe_ret = NULL;
   1064
   1065	if (seq_ports <= 0)
   1066		return 0;
   1067
   1068	hw = devm_kzalloc(card->dev, sizeof(*hw), GFP_KERNEL);
   1069	if (hw == NULL)
   1070		return -ENOMEM;
   1071	spin_lock_init(&hw->reg_lock);
   1072	hw->index = index;
   1073	hw->port1 = port;
   1074	hw->port2 = port + 0x400;
   1075	hw->port3 = port + 0x800;
   1076	if (!devm_request_region(card->dev, hw->port1, 4, "Emu8000-1") ||
   1077	    !devm_request_region(card->dev, hw->port2, 4, "Emu8000-2") ||
   1078	    !devm_request_region(card->dev, hw->port3, 4, "Emu8000-3")) {
   1079		snd_printk(KERN_ERR "sbawe: can't grab ports 0x%lx, 0x%lx, 0x%lx\n", hw->port1, hw->port2, hw->port3);
   1080		return -EBUSY;
   1081	}
   1082	hw->mem_size = 0;
   1083	hw->card = card;
   1084	hw->seq_ports = seq_ports;
   1085	hw->bass_level = 5;
   1086	hw->treble_level = 9;
   1087	hw->chorus_mode = 2;
   1088	hw->reverb_mode = 4;
   1089	hw->fm_chorus_depth = 0;
   1090	hw->fm_reverb_depth = 0;
   1091
   1092	if (snd_emu8000_detect(hw) < 0)
   1093		return -ENODEV;
   1094
   1095	snd_emu8000_init_hw(hw);
   1096	err = snd_emu8000_create_mixer(card, hw);
   1097	if (err < 0)
   1098		return err;
   1099#if IS_ENABLED(CONFIG_SND_SEQUENCER)
   1100	if (snd_seq_device_new(card, index, SNDRV_SEQ_DEV_ID_EMU8000,
   1101			       sizeof(struct snd_emu8000*), &awe) >= 0) {
   1102		strcpy(awe->name, "EMU-8000");
   1103		*(struct snd_emu8000 **)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw;
   1104	}
   1105#else
   1106	awe = NULL;
   1107#endif
   1108	if (awe_ret)
   1109		*awe_ret = awe;
   1110
   1111	return 0;
   1112}
   1113
   1114
   1115/*
   1116 * exported stuff
   1117 */
   1118
   1119EXPORT_SYMBOL(snd_emu8000_poke);
   1120EXPORT_SYMBOL(snd_emu8000_peek);
   1121EXPORT_SYMBOL(snd_emu8000_poke_dw);
   1122EXPORT_SYMBOL(snd_emu8000_peek_dw);
   1123EXPORT_SYMBOL(snd_emu8000_dma_chan);
   1124EXPORT_SYMBOL(snd_emu8000_init_fm);
   1125EXPORT_SYMBOL(snd_emu8000_load_chorus_fx);
   1126EXPORT_SYMBOL(snd_emu8000_load_reverb_fx);
   1127EXPORT_SYMBOL(snd_emu8000_update_chorus_mode);
   1128EXPORT_SYMBOL(snd_emu8000_update_reverb_mode);
   1129EXPORT_SYMBOL(snd_emu8000_update_equalizer);