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