2019-05-27 08:55:05 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-16 15:20:36 -07:00
|
|
|
/*
|
2007-10-15 09:50:19 +02:00
|
|
|
* Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
2023-07-15 18:08:39 +02:00
|
|
|
* James Courtier-Dutton <James@superbug.co.uk>
|
|
|
|
* Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
|
2005-04-16 15:20:36 -07:00
|
|
|
* Creative Labs, Inc.
|
|
|
|
*
|
2023-07-15 18:08:39 +02:00
|
|
|
* Routines for control of EMU10K1 chips
|
2005-04-16 15:20:36 -07:00
|
|
|
*/
|
|
|
|
|
2007-07-23 17:52:27 +01:00
|
|
|
#include <linux/sched.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/init.h>
|
2011-07-15 12:38:28 -04:00
|
|
|
#include <linux/module.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
#include <linux/interrupt.h>
|
2018-02-14 00:07:58 +01:00
|
|
|
#include <linux/iommu.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/vmalloc.h>
|
2006-01-16 16:34:20 +01:00
|
|
|
#include <linux/mutex.h>
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
#include <sound/core.h>
|
|
|
|
#include <sound/emu10k1.h>
|
2006-10-01 10:48:04 +01:00
|
|
|
#include <linux/firmware.h>
|
2005-04-16 15:20:36 -07:00
|
|
|
#include "p16v.h"
|
2005-11-11 23:39:05 +01:00
|
|
|
#include "tina2.h"
|
2006-12-06 15:58:02 +00:00
|
|
|
#include "p17v.h"
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2005-12-04 18:03:03 +01:00
|
|
|
|
2007-05-03 17:59:54 +02:00
|
|
|
#define HANA_FILENAME "emu/hana.fw"
|
|
|
|
#define DOCK_FILENAME "emu/audio_dock.fw"
|
2007-07-14 02:18:26 +01:00
|
|
|
#define EMU1010B_FILENAME "emu/emu1010b.fw"
|
|
|
|
#define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
|
2007-11-04 14:08:26 +00:00
|
|
|
#define EMU0404_FILENAME "emu/emu0404.fw"
|
2007-07-14 10:24:49 +01:00
|
|
|
#define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
|
2007-05-03 17:59:54 +02:00
|
|
|
|
|
|
|
MODULE_FIRMWARE(HANA_FILENAME);
|
|
|
|
MODULE_FIRMWARE(DOCK_FILENAME);
|
2007-07-14 02:18:26 +01:00
|
|
|
MODULE_FIRMWARE(EMU1010B_FILENAME);
|
|
|
|
MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
|
2007-11-04 14:08:26 +00:00
|
|
|
MODULE_FIRMWARE(EMU0404_FILENAME);
|
2007-07-14 10:24:49 +01:00
|
|
|
MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
|
2007-05-03 17:59:54 +02:00
|
|
|
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
/*************************************************************************
|
|
|
|
* EMU10K1 init / done
|
|
|
|
*************************************************************************/
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
void snd_emu10k1_voice_init(struct snd_emu10k1 *emu, int ch)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
2023-05-18 11:31:34 +02:00
|
|
|
snd_emu10k1_ptr_write_multiple(emu, ch,
|
|
|
|
DCYSUSV, 0,
|
|
|
|
VTFT, VTFT_FILTERTARGET_MASK,
|
|
|
|
CVCF, CVCF_CURRENTFILTER_MASK,
|
|
|
|
PTRX, 0,
|
|
|
|
CPF, 0,
|
|
|
|
CCR, 0,
|
|
|
|
|
|
|
|
PSST, 0,
|
|
|
|
DSL, 0x10,
|
|
|
|
CCCA, 0,
|
|
|
|
Z1, 0,
|
|
|
|
Z2, 0,
|
|
|
|
FXRT, 0x32100000,
|
|
|
|
|
|
|
|
// The rest is meaningless as long as DCYSUSV_CHANNELENABLE_MASK is zero
|
|
|
|
DCYSUSM, 0,
|
|
|
|
ATKHLDV, 0,
|
|
|
|
ATKHLDM, 0,
|
|
|
|
IP, 0,
|
|
|
|
IFATN, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK,
|
|
|
|
PEFE, 0,
|
|
|
|
FMMOD, 0,
|
|
|
|
TREMFRQ, 24, /* 1 Hz */
|
|
|
|
FM2FRQ2, 24, /* 1 Hz */
|
|
|
|
LFOVAL2, 0,
|
|
|
|
LFOVAL1, 0,
|
|
|
|
ENVVOL, 0,
|
|
|
|
ENVVAL, 0,
|
|
|
|
|
|
|
|
REGLIST_END);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* Audigy extra stuffs */
|
|
|
|
if (emu->audigy) {
|
2023-05-18 11:31:34 +02:00
|
|
|
snd_emu10k1_ptr_write_multiple(emu, ch,
|
|
|
|
A_CSBA, 0,
|
|
|
|
A_CSDC, 0,
|
|
|
|
A_CSFE, 0,
|
|
|
|
A_CSHG, 0,
|
|
|
|
A_FXRT1, 0x03020100,
|
|
|
|
A_FXRT2, 0x07060504,
|
|
|
|
A_SENDAMOUNTS, 0,
|
|
|
|
REGLIST_END);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-05 15:47:29 +01:00
|
|
|
static const unsigned int spi_dac_init[] = {
|
2005-12-21 22:05:29 +01:00
|
|
|
0x00ff,
|
|
|
|
0x02ff,
|
|
|
|
0x0400,
|
|
|
|
0x0520,
|
|
|
|
0x0600,
|
|
|
|
0x08ff,
|
|
|
|
0x0aff,
|
|
|
|
0x0cff,
|
|
|
|
0x0eff,
|
|
|
|
0x10ff,
|
|
|
|
0x1200,
|
|
|
|
0x1400,
|
|
|
|
0x1480,
|
|
|
|
0x1800,
|
|
|
|
0x1aff,
|
|
|
|
0x1cff,
|
|
|
|
0x1e00,
|
|
|
|
0x0530,
|
|
|
|
0x0602,
|
|
|
|
0x0622,
|
|
|
|
0x1400,
|
|
|
|
};
|
2006-12-06 15:58:02 +00:00
|
|
|
|
2020-01-05 15:47:29 +01:00
|
|
|
static const unsigned int i2c_adc_init[][2] = {
|
2006-12-06 15:58:02 +00:00
|
|
|
{ 0x17, 0x00 }, /* Reset */
|
|
|
|
{ 0x07, 0x00 }, /* Timeout */
|
|
|
|
{ 0x0b, 0x22 }, /* Interface control */
|
|
|
|
{ 0x0c, 0x22 }, /* Master mode control */
|
|
|
|
{ 0x0d, 0x08 }, /* Powerdown control */
|
|
|
|
{ 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */
|
|
|
|
{ 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */
|
|
|
|
{ 0x10, 0x7b }, /* ALC Control 1 */
|
|
|
|
{ 0x11, 0x00 }, /* ALC Control 2 */
|
|
|
|
{ 0x12, 0x32 }, /* ALC Control 3 */
|
|
|
|
{ 0x13, 0x00 }, /* Noise gate control */
|
|
|
|
{ 0x14, 0xa6 }, /* Limiter control */
|
2008-10-23 18:51:00 +02:00
|
|
|
{ 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for A2ZS Notebook */
|
2006-12-06 15:58:02 +00:00
|
|
|
};
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2023-04-22 15:24:29 +02:00
|
|
|
static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
unsigned int silent_page;
|
2005-11-17 16:14:10 +01:00
|
|
|
int ch;
|
2006-12-06 15:58:02 +00:00
|
|
|
u32 tmp;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* disable audio and lock cache */
|
2008-10-23 18:51:00 +02:00
|
|
|
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK |
|
|
|
|
HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
outl(0, emu->port + INTE);
|
2023-04-22 18:10:15 +02:00
|
|
|
|
2023-05-18 11:31:34 +02:00
|
|
|
snd_emu10k1_ptr_write_multiple(emu, 0,
|
|
|
|
/* reset recording buffers */
|
|
|
|
MICBS, ADCBS_BUFSIZE_NONE,
|
|
|
|
MICBA, 0,
|
|
|
|
FXBS, ADCBS_BUFSIZE_NONE,
|
|
|
|
FXBA, 0,
|
|
|
|
ADCBS, ADCBS_BUFSIZE_NONE,
|
|
|
|
ADCBA, 0,
|
|
|
|
|
|
|
|
/* disable channel interrupt */
|
|
|
|
CLIEL, 0,
|
|
|
|
CLIEH, 0,
|
|
|
|
|
|
|
|
/* disable stop on loop end */
|
|
|
|
SOLEL, 0,
|
|
|
|
SOLEH, 0,
|
|
|
|
|
|
|
|
REGLIST_END);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
if (emu->audigy) {
|
2005-04-16 15:20:36 -07:00
|
|
|
/* set SPDIF bypass mode */
|
|
|
|
snd_emu10k1_ptr_write(emu, SPBYPASS, 0, SPBYPASS_FORMAT);
|
|
|
|
/* enable rear left + rear right AC97 slots */
|
2005-11-17 16:14:10 +01:00
|
|
|
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_REAR_RIGHT |
|
|
|
|
AC97SLOT_REAR_LEFT);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* init envelope engine */
|
2005-11-17 16:14:10 +01:00
|
|
|
for (ch = 0; ch < NUM_G; ch++)
|
2005-04-16 15:20:36 -07:00
|
|
|
snd_emu10k1_voice_init(emu, ch);
|
|
|
|
|
2023-05-18 11:31:34 +02:00
|
|
|
snd_emu10k1_ptr_write_multiple(emu, 0,
|
|
|
|
SPCS0, emu->spdif_bits[0],
|
|
|
|
SPCS1, emu->spdif_bits[1],
|
|
|
|
SPCS2, emu->spdif_bits[2],
|
|
|
|
REGLIST_END);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2023-04-22 18:10:21 +02:00
|
|
|
if (emu->card_capabilities->emu_model) {
|
|
|
|
} else if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
|
2005-04-16 15:20:36 -07:00
|
|
|
/* Hacks for Alice3 to work independent of haP16V driver */
|
2008-10-23 18:51:00 +02:00
|
|
|
/* Setup SRCMulti_I2S SamplingRate */
|
2023-04-22 18:10:20 +02:00
|
|
|
snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, 0, A_I2S_CAPTURE_96000);
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
|
|
|
|
snd_emu10k1_ptr20_write(emu, SRCSel, 0, 0x14);
|
|
|
|
/* Setup SRCMulti Input Audio Enable */
|
|
|
|
/* Use 0xFFFFFFFF to enable P16V sounds. */
|
|
|
|
snd_emu10k1_ptr20_write(emu, SRCMULTI_ENABLE, 0, 0xFFFFFFFF);
|
|
|
|
|
|
|
|
/* Enabled Phased (8-channel) P16V playback */
|
|
|
|
outl(0x0201, emu->port + HCFG2);
|
|
|
|
/* Set playback routing. */
|
2005-04-10 15:43:35 +02:00
|
|
|
snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, 0x78e4);
|
2023-04-22 18:10:21 +02:00
|
|
|
} else if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */
|
2005-04-16 15:20:36 -07:00
|
|
|
/* Hacks for Alice3 to work independent of haP16V driver */
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev, "Audigy2 value: Special config.\n");
|
2008-10-23 18:51:00 +02:00
|
|
|
/* Setup SRCMulti_I2S SamplingRate */
|
2023-04-22 18:10:20 +02:00
|
|
|
snd_emu10k1_ptr_write(emu, A_I2S_CAPTURE_RATE, 0, A_I2S_CAPTURE_96000);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
|
2023-04-22 18:10:20 +02:00
|
|
|
snd_emu10k1_ptr20_write(emu, P17V_SRCSel, 0, 0x14);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* Setup SRCMulti Input Audio Enable */
|
2023-04-22 18:10:20 +02:00
|
|
|
snd_emu10k1_ptr20_write(emu, P17V_MIXER_I2S_ENABLE, 0, 0xFF000000);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* Setup SPDIF Out Audio Enable */
|
|
|
|
/* The Audigy 2 Value has a separate SPDIF out,
|
|
|
|
* so no need for a mixer switch
|
|
|
|
*/
|
2023-04-22 18:10:20 +02:00
|
|
|
snd_emu10k1_ptr20_write(emu, P17V_MIXER_SPDIF_ENABLE, 0, 0xFF000000);
|
|
|
|
|
2023-04-21 16:10:01 +02:00
|
|
|
tmp = inw(emu->port + A_IOCFG) & ~0x8; /* Clear bit 3 */
|
|
|
|
outw(tmp, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
2005-12-21 15:06:08 +01:00
|
|
|
if (emu->card_capabilities->spi_dac) { /* Audigy 2 ZS Notebook with DAC Wolfson WM8768/WM8568 */
|
2005-12-21 22:05:29 +01:00
|
|
|
int size, n;
|
|
|
|
|
|
|
|
size = ARRAY_SIZE(spi_dac_init);
|
2006-10-01 10:48:04 +01:00
|
|
|
for (n = 0; n < size; n++)
|
2005-12-21 22:05:29 +01:00
|
|
|
snd_emu10k1_spi_write(emu, spi_dac_init[n]);
|
|
|
|
|
2005-12-21 15:06:08 +01:00
|
|
|
snd_emu10k1_ptr20_write(emu, 0x60, 0, 0x10);
|
2005-12-21 15:31:02 +01:00
|
|
|
/* Enable GPIOs
|
|
|
|
* GPIO0: Unknown
|
|
|
|
* GPIO1: Speakers-enabled.
|
|
|
|
* GPIO2: Unknown
|
|
|
|
* GPIO3: Unknown
|
|
|
|
* GPIO4: IEC958 Output on.
|
|
|
|
* GPIO5: Unknown
|
|
|
|
* GPIO6: Unknown
|
|
|
|
* GPIO7: Unknown
|
|
|
|
*/
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
|
2005-12-21 15:06:08 +01:00
|
|
|
}
|
2006-12-06 15:58:02 +00:00
|
|
|
if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
|
|
|
|
int size, n;
|
|
|
|
|
|
|
|
snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f);
|
2023-04-21 16:10:01 +02:00
|
|
|
tmp = inw(emu->port + A_IOCFG);
|
|
|
|
outw(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */
|
|
|
|
tmp = inw(emu->port + A_IOCFG);
|
2006-12-06 15:58:02 +00:00
|
|
|
size = ARRAY_SIZE(i2c_adc_init);
|
|
|
|
for (n = 0; n < size; n++)
|
|
|
|
snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]);
|
2008-10-23 18:51:00 +02:00
|
|
|
for (n = 0; n < 4; n++) {
|
|
|
|
emu->i2c_capture_volume[n][0] = 0xcf;
|
|
|
|
emu->i2c_capture_volume[n][1] = 0xcf;
|
2006-12-06 15:58:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr);
|
|
|
|
snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu10k1_ptr_write(emu, TCBS, 0, TCBS_BUFFSIZE_256K); /* taken from original driver */
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2015-04-28 21:57:29 +02:00
|
|
|
silent_page = (emu->silent_page.addr << emu->address_mode) | (emu->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);
|
2005-04-16 15:20:36 -07:00
|
|
|
for (ch = 0; ch < NUM_G; ch++) {
|
|
|
|
snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page);
|
|
|
|
snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page);
|
|
|
|
}
|
|
|
|
|
2007-11-04 14:08:26 +00:00
|
|
|
if (emu->card_capabilities->emu_model) {
|
2006-10-01 10:48:04 +01:00
|
|
|
outl(HCFG_AUTOMUTE_ASYNC |
|
|
|
|
HCFG_EMU32_SLAVE |
|
|
|
|
HCFG_AUDIOENABLE, emu->port + HCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
/*
|
|
|
|
* Hokay, setup HCFG
|
|
|
|
* Mute Disable Audio = 0
|
|
|
|
* Lock Tank Memory = 1
|
|
|
|
* Lock Sound Memory = 0
|
|
|
|
* Auto Mute = 1
|
|
|
|
*/
|
2006-10-01 10:48:04 +01:00
|
|
|
} else if (emu->audigy) {
|
2005-04-16 15:20:36 -07:00
|
|
|
if (emu->revision == 4) /* audigy2 */
|
|
|
|
outl(HCFG_AUDIOENABLE |
|
|
|
|
HCFG_AC3ENABLE_CDSPDIF |
|
|
|
|
HCFG_AC3ENABLE_GPSPDIF |
|
|
|
|
HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
|
|
|
|
else
|
|
|
|
outl(HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
|
2005-07-02 16:33:34 +02:00
|
|
|
/* FIXME: Remove all these emu->model and replace it with a card recognition parameter,
|
|
|
|
* e.g. card_capabilities->joystick */
|
2005-04-16 15:20:36 -07:00
|
|
|
} else if (emu->model == 0x20 ||
|
|
|
|
emu->model == 0xc400 ||
|
|
|
|
(emu->model == 0x21 && emu->revision < 6))
|
|
|
|
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE, emu->port + HCFG);
|
|
|
|
else
|
2008-10-23 18:51:00 +02:00
|
|
|
/* With on-chip joystick */
|
2005-04-16 15:20:36 -07:00
|
|
|
outl(HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE, emu->port + HCFG);
|
|
|
|
|
|
|
|
if (enable_ir) { /* enable IR for SB Live */
|
2007-11-04 14:08:26 +00:00
|
|
|
if (emu->card_capabilities->emu_model) {
|
2006-10-01 10:48:04 +01:00
|
|
|
; /* Disable all access to A_IOCFG for the emu1010 */
|
2006-12-06 15:58:02 +00:00
|
|
|
} else if (emu->card_capabilities->i2c_adc) {
|
|
|
|
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
|
2005-12-04 18:03:03 +01:00
|
|
|
} else if (emu->audigy) {
|
2023-04-21 16:10:01 +02:00
|
|
|
u16 reg = inw(emu->port + A_IOCFG);
|
|
|
|
outw(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
udelay(500);
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(reg | A_IOCFG_GPOUT1 | A_IOCFG_GPOUT2, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
udelay(100);
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(reg, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
} else {
|
|
|
|
unsigned int reg = inl(emu->port + HCFG);
|
|
|
|
outl(reg | HCFG_GPOUT2, emu->port + HCFG);
|
|
|
|
udelay(500);
|
|
|
|
outl(reg | HCFG_GPOUT1 | HCFG_GPOUT2, emu->port + HCFG);
|
|
|
|
udelay(100);
|
|
|
|
outl(reg, emu->port + HCFG);
|
2008-10-23 18:51:00 +02:00
|
|
|
}
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2007-11-04 14:08:26 +00:00
|
|
|
if (emu->card_capabilities->emu_model) {
|
2006-10-01 10:48:04 +01:00
|
|
|
; /* Disable all access to A_IOCFG for the emu1010 */
|
2006-12-06 15:58:02 +00:00
|
|
|
} else if (emu->card_capabilities->i2c_adc) {
|
|
|
|
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
|
2005-12-04 18:03:03 +01:00
|
|
|
} else if (emu->audigy) { /* enable analog output */
|
2023-04-21 16:10:01 +02:00
|
|
|
u16 reg = inw(emu->port + A_IOCFG);
|
|
|
|
outw(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2015-04-28 21:57:29 +02:00
|
|
|
if (emu->address_mode == 0) {
|
|
|
|
/* use 16M in 4G */
|
|
|
|
outl(inl(emu->port + HCFG) | HCFG_EXPANDED_MEM, emu->port + HCFG);
|
|
|
|
}
|
|
|
|
|
2005-11-17 16:14:10 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2005-11-17 16:14:10 +01:00
|
|
|
static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu)
|
|
|
|
{
|
2005-04-16 15:20:36 -07:00
|
|
|
/*
|
|
|
|
* Enable the audio bit
|
|
|
|
*/
|
|
|
|
outl(inl(emu->port + HCFG) | HCFG_AUDIOENABLE, emu->port + HCFG);
|
|
|
|
|
|
|
|
/* Enable analog/digital outs on audigy */
|
2007-11-04 14:08:26 +00:00
|
|
|
if (emu->card_capabilities->emu_model) {
|
2006-10-01 10:48:04 +01:00
|
|
|
; /* Disable all access to A_IOCFG for the emu1010 */
|
2006-12-06 15:58:02 +00:00
|
|
|
} else if (emu->card_capabilities->i2c_adc) {
|
|
|
|
; /* Disable A_IOCFG for Audigy 2 ZS Notebook */
|
2005-12-04 18:03:03 +01:00
|
|
|
} else if (emu->audigy) {
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(inw(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG);
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2005-07-02 16:33:34 +02:00
|
|
|
if (emu->card_capabilities->ca0151_chip) { /* audigy2 */
|
2005-04-16 15:20:36 -07:00
|
|
|
/* Unmute Analog now. Set GPO6 to 1 for Apollo.
|
|
|
|
* This has to be done after init ALice3 I2SOut beyond 48KHz.
|
|
|
|
* So, sequence is important. */
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(inw(emu->port + A_IOCFG) | 0x0040, emu->port + A_IOCFG);
|
2005-07-02 16:33:34 +02:00
|
|
|
} else if (emu->card_capabilities->ca0108_chip) { /* audigy2 value */
|
2005-04-16 15:20:36 -07:00
|
|
|
/* Unmute Analog now. */
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(inw(emu->port + A_IOCFG) | 0x0060, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
} else {
|
|
|
|
/* Disable routing from AC97 line out to Front speakers */
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(inw(emu->port + A_IOCFG) | 0x0080, emu->port + A_IOCFG);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
}
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
unsigned int tmp;
|
|
|
|
/* FIXME: the following routine disables LiveDrive-II !! */
|
2008-10-23 18:51:00 +02:00
|
|
|
/* TOSLink detection */
|
2005-04-16 15:20:36 -07:00
|
|
|
emu->tos_link = 0;
|
|
|
|
tmp = inl(emu->port + HCFG);
|
|
|
|
if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
|
|
|
|
outl(tmp|0x800, emu->port + HCFG);
|
|
|
|
udelay(50);
|
|
|
|
if (tmp != (inl(emu->port + HCFG) & ~0x800)) {
|
|
|
|
emu->tos_link = 1;
|
|
|
|
outl(tmp, emu->port + HCFG);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-07-10 08:59:55 +02:00
|
|
|
if (emu->card_capabilities->emu_model)
|
|
|
|
snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE | INTE_A_GPIOENABLE);
|
|
|
|
else
|
|
|
|
snd_emu10k1_intr_enable(emu, INTE_PCIERRORENABLE);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
int snd_emu10k1_done(struct snd_emu10k1 *emu)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
outl(0, emu->port + INTE);
|
|
|
|
|
|
|
|
/*
|
2023-05-18 11:31:34 +02:00
|
|
|
* Shutdown the voices
|
2005-04-16 15:20:36 -07:00
|
|
|
*/
|
|
|
|
for (ch = 0; ch < NUM_G; ch++) {
|
2023-05-18 11:31:34 +02:00
|
|
|
snd_emu10k1_ptr_write_multiple(emu, ch,
|
|
|
|
DCYSUSV, 0,
|
|
|
|
VTFT, 0,
|
|
|
|
CVCF, 0,
|
|
|
|
PTRX, 0,
|
|
|
|
CPF, 0,
|
|
|
|
REGLIST_END);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2023-05-18 11:31:34 +02:00
|
|
|
// stop the DSP
|
2005-04-16 15:20:36 -07:00
|
|
|
if (emu->audigy)
|
|
|
|
snd_emu10k1_ptr_write(emu, A_DBG, 0, A_DBG_SINGLE_STEP);
|
|
|
|
else
|
|
|
|
snd_emu10k1_ptr_write(emu, DBG, 0, EMU10K1_DBG_SINGLE_STEP);
|
|
|
|
|
2023-05-18 11:31:34 +02:00
|
|
|
snd_emu10k1_ptr_write_multiple(emu, 0,
|
|
|
|
/* reset recording buffers */
|
|
|
|
MICBS, 0,
|
|
|
|
MICBA, 0,
|
|
|
|
FXBS, 0,
|
|
|
|
FXBA, 0,
|
|
|
|
FXWC, 0,
|
|
|
|
ADCBS, ADCBS_BUFSIZE_NONE,
|
|
|
|
ADCBA, 0,
|
|
|
|
TCBS, TCBS_BUFFSIZE_16K,
|
|
|
|
TCB, 0,
|
|
|
|
|
|
|
|
/* disable channel interrupt */
|
|
|
|
CLIEL, 0,
|
|
|
|
CLIEH, 0,
|
|
|
|
SOLEL, 0,
|
|
|
|
SOLEH, 0,
|
|
|
|
|
|
|
|
PTB, 0,
|
|
|
|
|
|
|
|
REGLIST_END);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* disable audio and lock cache */
|
|
|
|
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
* ECARD functional implementation
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
|
|
/* In A1 Silicon, these bits are in the HC register */
|
|
|
|
#define HOOKN_BIT (1L << 12)
|
|
|
|
#define HANDN_BIT (1L << 11)
|
|
|
|
#define PULSEN_BIT (1L << 10)
|
|
|
|
|
|
|
|
#define EC_GDI1 (1 << 13)
|
|
|
|
#define EC_GDI0 (1 << 14)
|
|
|
|
|
|
|
|
#define EC_NUM_CONTROL_BITS 20
|
|
|
|
|
|
|
|
#define EC_AC3_DATA_SELN 0x0001L
|
|
|
|
#define EC_EE_DATA_SEL 0x0002L
|
|
|
|
#define EC_EE_CNTRL_SELN 0x0004L
|
|
|
|
#define EC_EECLK 0x0008L
|
|
|
|
#define EC_EECS 0x0010L
|
|
|
|
#define EC_EESDO 0x0020L
|
|
|
|
#define EC_TRIM_CSN 0x0040L
|
|
|
|
#define EC_TRIM_SCLK 0x0080L
|
|
|
|
#define EC_TRIM_SDATA 0x0100L
|
|
|
|
#define EC_TRIM_MUTEN 0x0200L
|
|
|
|
#define EC_ADCCAL 0x0400L
|
|
|
|
#define EC_ADCRSTN 0x0800L
|
|
|
|
#define EC_DACCAL 0x1000L
|
|
|
|
#define EC_DACMUTEN 0x2000L
|
|
|
|
#define EC_LEDN 0x4000L
|
|
|
|
|
|
|
|
#define EC_SPDIF0_SEL_SHIFT 15
|
|
|
|
#define EC_SPDIF1_SEL_SHIFT 17
|
|
|
|
#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT)
|
|
|
|
#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT)
|
|
|
|
#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK)
|
|
|
|
#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK)
|
|
|
|
#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should
|
|
|
|
* be incremented any time the EEPROM's
|
|
|
|
* format is changed. */
|
|
|
|
|
|
|
|
#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */
|
|
|
|
|
|
|
|
/* Addresses for special values stored in to EEPROM */
|
|
|
|
#define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */
|
|
|
|
#define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */
|
|
|
|
#define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */
|
|
|
|
|
|
|
|
#define EC_LAST_PROMFILE_ADDR 0x2f
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
#define EC_SERIALNUM_ADDR 0x30 /* First word of serial number. The
|
2005-04-16 15:20:36 -07:00
|
|
|
* can be up to 30 characters in length
|
|
|
|
* and is stored as a NULL-terminated
|
|
|
|
* ASCII string. Any unused bytes must be
|
|
|
|
* filled with zeros */
|
|
|
|
#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */
|
|
|
|
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
/* Most of this stuff is pretty self-evident. According to the hardware
|
|
|
|
* dudes, we need to leave the ADCCAL bit low in order to avoid a DC
|
2005-04-16 15:20:36 -07:00
|
|
|
* offset problem. Weird.
|
|
|
|
*/
|
|
|
|
#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | \
|
|
|
|
EC_TRIM_CSN)
|
|
|
|
|
|
|
|
|
|
|
|
#define EC_DEFAULT_ADC_GAIN 0xC4C4
|
|
|
|
#define EC_DEFAULT_SPDIF0_SEL 0x0
|
|
|
|
#define EC_DEFAULT_SPDIF1_SEL 0x4
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* @func Clock bits into the Ecard's control latch. The Ecard uses a
|
|
|
|
* control latch will is loaded bit-serially by toggling the Modem control
|
|
|
|
* lines from function 2 on the E8010. This function hides these details
|
|
|
|
* and presents the illusion that we are actually writing to a distinct
|
|
|
|
* register.
|
|
|
|
*/
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
static void snd_emu10k1_ecard_write(struct snd_emu10k1 *emu, unsigned int value)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
unsigned short count;
|
|
|
|
unsigned int data;
|
|
|
|
unsigned long hc_port;
|
|
|
|
unsigned int hc_value;
|
|
|
|
|
|
|
|
hc_port = emu->port + HCFG;
|
|
|
|
hc_value = inl(hc_port) & ~(HOOKN_BIT | HANDN_BIT | PULSEN_BIT);
|
|
|
|
outl(hc_value, hc_port);
|
|
|
|
|
|
|
|
for (count = 0; count < EC_NUM_CONTROL_BITS; count++) {
|
|
|
|
|
|
|
|
/* Set up the value */
|
|
|
|
data = ((value & 0x1) ? PULSEN_BIT : 0);
|
|
|
|
value >>= 1;
|
|
|
|
|
|
|
|
outl(hc_value | data, hc_port);
|
|
|
|
|
|
|
|
/* Clock the shift register */
|
|
|
|
outl(hc_value | data | HANDN_BIT, hc_port);
|
|
|
|
outl(hc_value | data, hc_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Latch the bits */
|
|
|
|
outl(hc_value | HOOKN_BIT, hc_port);
|
|
|
|
outl(hc_value, hc_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
|
|
* @func Set the gain of the ECARD's CS3310 Trim/gain controller. The
|
|
|
|
* trim value consists of a 16bit value which is composed of two
|
|
|
|
* 8 bit gain/trim values, one for the left channel and one for the
|
|
|
|
* right channel. The following table maps from the Gain/Attenuation
|
|
|
|
* value in decibels into the corresponding bit pattern for a single
|
|
|
|
* channel.
|
|
|
|
*/
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
static void snd_emu10k1_ecard_setadcgain(struct snd_emu10k1 *emu,
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned short gain)
|
|
|
|
{
|
|
|
|
unsigned int bit;
|
|
|
|
|
|
|
|
/* Enable writing to the TRIM registers */
|
|
|
|
snd_emu10k1_ecard_write(emu, emu->ecard_ctrl & ~EC_TRIM_CSN);
|
|
|
|
|
|
|
|
/* Do it again to insure that we meet hold time requirements */
|
|
|
|
snd_emu10k1_ecard_write(emu, emu->ecard_ctrl & ~EC_TRIM_CSN);
|
|
|
|
|
|
|
|
for (bit = (1 << 15); bit; bit >>= 1) {
|
|
|
|
unsigned int value;
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
value = emu->ecard_ctrl & ~(EC_TRIM_CSN | EC_TRIM_SDATA);
|
|
|
|
|
|
|
|
if (gain & bit)
|
|
|
|
value |= EC_TRIM_SDATA;
|
|
|
|
|
|
|
|
/* Clock the bit */
|
|
|
|
snd_emu10k1_ecard_write(emu, value);
|
|
|
|
snd_emu10k1_ecard_write(emu, value | EC_TRIM_SCLK);
|
|
|
|
snd_emu10k1_ecard_write(emu, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
snd_emu10k1_ecard_write(emu, emu->ecard_ctrl);
|
|
|
|
}
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
static int snd_emu10k1_ecard_init(struct snd_emu10k1 *emu)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
|
|
|
unsigned int hc_value;
|
|
|
|
|
|
|
|
/* Set up the initial settings */
|
|
|
|
emu->ecard_ctrl = EC_RAW_RUN_MODE |
|
|
|
|
EC_SPDIF0_SELECT(EC_DEFAULT_SPDIF0_SEL) |
|
|
|
|
EC_SPDIF1_SELECT(EC_DEFAULT_SPDIF1_SEL);
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
/* Step 0: Set the codec type in the hardware control register
|
2005-04-16 15:20:36 -07:00
|
|
|
* and enable audio output */
|
|
|
|
hc_value = inl(emu->port + HCFG);
|
|
|
|
outl(hc_value | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S, emu->port + HCFG);
|
|
|
|
inl(emu->port + HCFG);
|
|
|
|
|
|
|
|
/* Step 1: Turn off the led and deassert TRIM_CS */
|
|
|
|
snd_emu10k1_ecard_write(emu, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
|
|
|
|
|
|
|
|
/* Step 2: Calibrate the ADC and DAC */
|
|
|
|
snd_emu10k1_ecard_write(emu, EC_DACCAL | EC_LEDN | EC_TRIM_CSN);
|
|
|
|
|
|
|
|
/* Step 3: Wait for awhile; XXX We can't get away with this
|
|
|
|
* under a real operating system; we'll need to block and wait that
|
|
|
|
* way. */
|
|
|
|
snd_emu10k1_wait(emu, 48000);
|
|
|
|
|
|
|
|
/* Step 4: Switch off the DAC and ADC calibration. Note
|
|
|
|
* That ADC_CAL is actually an inverted signal, so we assert
|
|
|
|
* it here to stop calibration. */
|
|
|
|
snd_emu10k1_ecard_write(emu, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
|
|
|
|
|
|
|
|
/* Step 4: Switch into run mode */
|
|
|
|
snd_emu10k1_ecard_write(emu, emu->ecard_ctrl);
|
|
|
|
|
|
|
|
/* Step 5: Set the analog input gain */
|
|
|
|
snd_emu10k1_ecard_setadcgain(emu, EC_DEFAULT_ADC_GAIN);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu)
|
2005-10-31 10:27:41 +00:00
|
|
|
{
|
|
|
|
unsigned long special_port;
|
2020-07-02 14:35:52 -05:00
|
|
|
__always_unused unsigned int value;
|
2005-10-31 10:27:41 +00:00
|
|
|
|
|
|
|
/* Special initialisation routine
|
|
|
|
* before the rest of the IO-Ports become active.
|
|
|
|
*/
|
|
|
|
special_port = emu->port + 0x38;
|
|
|
|
value = inl(special_port);
|
|
|
|
outl(0x00d00000, special_port);
|
|
|
|
value = inl(special_port);
|
|
|
|
outl(0x00d00001, special_port);
|
|
|
|
value = inl(special_port);
|
|
|
|
outl(0x00d0005f, special_port);
|
|
|
|
value = inl(special_port);
|
|
|
|
outl(0x00d0007f, special_port);
|
|
|
|
value = inl(special_port);
|
|
|
|
outl(0x0090007f, special_port);
|
|
|
|
value = inl(special_port);
|
|
|
|
|
2005-11-11 23:39:05 +01:00
|
|
|
snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */
|
2007-11-10 17:55:14 +00:00
|
|
|
/* Delay to give time for ADC chip to switch on. It needs 113ms */
|
|
|
|
msleep(200);
|
2005-10-31 10:27:41 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-02 18:13:06 +01:00
|
|
|
/* firmware file names, per model, init-fw and dock-fw (optional) */
|
|
|
|
static const char * const firmware_names[5][2] = {
|
|
|
|
[EMU_MODEL_EMU1010] = {
|
|
|
|
HANA_FILENAME, DOCK_FILENAME
|
|
|
|
},
|
|
|
|
[EMU_MODEL_EMU1010B] = {
|
|
|
|
EMU1010B_FILENAME, MICRO_DOCK_FILENAME
|
|
|
|
},
|
|
|
|
[EMU_MODEL_EMU1616] = {
|
|
|
|
EMU1010_NOTEBOOK_FILENAME, MICRO_DOCK_FILENAME
|
|
|
|
},
|
|
|
|
[EMU_MODEL_EMU0404] = {
|
|
|
|
EMU0404_FILENAME, NULL
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock,
|
|
|
|
const struct firmware **fw)
|
|
|
|
{
|
|
|
|
const char *filename;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
if (!*fw) {
|
|
|
|
filename = firmware_names[emu->card_capabilities->emu_model][dock];
|
|
|
|
if (!filename)
|
|
|
|
return 0;
|
|
|
|
err = request_firmware(fw, filename, &emu->pci->dev);
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2024-04-28 11:37:17 +02:00
|
|
|
snd_emu1010_load_firmware_entry(emu, dock, *fw);
|
2024-04-28 11:37:15 +02:00
|
|
|
return 0;
|
2016-11-02 18:13:06 +01:00
|
|
|
}
|
|
|
|
|
2024-04-28 11:37:12 +02:00
|
|
|
static void snd_emu1010_load_dock_firmware(struct snd_emu10k1 *emu)
|
|
|
|
{
|
|
|
|
u32 tmp, tmp2;
|
|
|
|
int err;
|
|
|
|
|
2024-04-28 11:37:15 +02:00
|
|
|
// The docking events clearly arrive prematurely - while the
|
|
|
|
// Dock's FPGA seems to be successfully programmed, the Dock
|
|
|
|
// fails to initialize subsequently if we don't give it some
|
|
|
|
// time to "warm up" here.
|
|
|
|
msleep(200);
|
|
|
|
|
2024-04-28 11:37:12 +02:00
|
|
|
dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n");
|
|
|
|
err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw);
|
|
|
|
if (err < 0)
|
|
|
|
return;
|
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0);
|
|
|
|
|
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp);
|
|
|
|
dev_dbg(emu->card->dev, "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp);
|
|
|
|
if ((tmp & 0x1f) != 0x15) {
|
|
|
|
/* FPGA failed to be programmed */
|
|
|
|
dev_err(emu->card->dev,
|
|
|
|
"emu1010: Loading Audio Dock Firmware failed, reg = 0x%x\n",
|
|
|
|
tmp);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dev_info(emu->card->dev, "emu1010: Audio Dock Firmware loaded\n");
|
|
|
|
|
|
|
|
snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp);
|
|
|
|
snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2);
|
|
|
|
dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2);
|
|
|
|
|
|
|
|
/* Allow DLL to settle, to sync clocking between 1010 and Dock */
|
|
|
|
msleep(10);
|
|
|
|
}
|
|
|
|
|
2024-04-28 11:37:13 +02:00
|
|
|
static void emu1010_dock_event(struct snd_emu10k1 *emu)
|
2007-12-14 12:43:00 +01:00
|
|
|
{
|
2024-04-28 11:37:12 +02:00
|
|
|
u32 reg;
|
2007-07-23 17:52:27 +01:00
|
|
|
|
2016-11-02 18:38:39 +01:00
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */
|
|
|
|
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) {
|
|
|
|
/* Audio Dock attached */
|
2024-04-28 11:37:12 +02:00
|
|
|
snd_emu1010_load_dock_firmware(emu);
|
2016-11-02 18:38:39 +01:00
|
|
|
/* Unmute all. Default is muted after a firmware load */
|
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
2024-04-28 11:37:11 +02:00
|
|
|
} else if (!(reg & EMU_HANA_OPTION_DOCK_ONLINE)) {
|
|
|
|
/* Audio Dock removed */
|
|
|
|
dev_info(emu->card->dev, "emu1010: Audio Dock detached\n");
|
|
|
|
/* The hardware auto-mutes all, so we unmute again */
|
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
2023-07-10 08:59:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-28 11:37:13 +02:00
|
|
|
static void emu1010_clock_event(struct snd_emu10k1 *emu)
|
2023-07-15 18:07:38 +02:00
|
|
|
{
|
|
|
|
struct snd_ctl_elem_id id;
|
|
|
|
|
|
|
|
spin_lock_irq(&emu->reg_lock);
|
|
|
|
// This is the only thing that can actually happen.
|
|
|
|
emu->emu1010.clock_source = emu->emu1010.clock_fallback;
|
|
|
|
emu->emu1010.wclock = 1 - emu->emu1010.clock_source;
|
|
|
|
snd_emu1010_update_clock(emu);
|
|
|
|
spin_unlock_irq(&emu->reg_lock);
|
|
|
|
snd_ctl_build_ioff(&id, emu->ctl_clock_source, 0);
|
|
|
|
snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
|
|
|
|
}
|
|
|
|
|
2024-04-28 11:37:13 +02:00
|
|
|
static void emu1010_work(struct work_struct *work)
|
2023-07-10 08:59:55 +02:00
|
|
|
{
|
2024-04-28 11:37:13 +02:00
|
|
|
struct snd_emu10k1 *emu;
|
2023-07-10 08:59:55 +02:00
|
|
|
u32 sts;
|
|
|
|
|
2024-04-28 11:37:13 +02:00
|
|
|
emu = container_of(work, struct snd_emu10k1, emu1010.work);
|
|
|
|
if (emu->card->shutdown)
|
|
|
|
return;
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
|
|
if (emu->suspend)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
2024-04-28 11:37:14 +02:00
|
|
|
snd_emu1010_fpga_lock(emu);
|
|
|
|
|
2023-07-10 08:59:55 +02:00
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &sts);
|
2024-04-28 11:37:11 +02:00
|
|
|
|
|
|
|
// The distinction of the IRQ status bits is unreliable,
|
|
|
|
// so we dispatch later based on option card status.
|
|
|
|
if (sts & (EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST))
|
2024-04-28 11:37:13 +02:00
|
|
|
emu1010_dock_event(emu);
|
2024-04-28 11:37:11 +02:00
|
|
|
|
2023-07-15 18:07:38 +02:00
|
|
|
if (sts & EMU_HANA_IRQ_WCLK_CHANGED)
|
2024-04-28 11:37:13 +02:00
|
|
|
emu1010_clock_event(emu);
|
2024-04-28 11:37:14 +02:00
|
|
|
|
|
|
|
snd_emu1010_fpga_unlock(emu);
|
2024-04-28 11:37:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void emu1010_interrupt(struct snd_emu10k1 *emu)
|
|
|
|
{
|
|
|
|
// We get an interrupt on each GPIO input pin change, but we
|
|
|
|
// care only about the ones triggered by the dedicated pin.
|
|
|
|
u16 sts = inw(emu->port + A_GPIO);
|
|
|
|
u16 bit = emu->card_capabilities->ca0108_chip ? 0x2000 : 0x8000;
|
|
|
|
if (!(sts & bit))
|
|
|
|
return;
|
|
|
|
|
|
|
|
schedule_work(&emu->emu1010.work);
|
2007-07-23 17:52:27 +01:00
|
|
|
}
|
|
|
|
|
2007-06-11 12:21:20 +02:00
|
|
|
/*
|
|
|
|
* Current status of the driver:
|
|
|
|
* ----------------------------
|
|
|
|
* * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz)
|
|
|
|
* * PCM device nb. 2:
|
|
|
|
* 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
|
|
|
|
* 16 x 32-bit capture - snd_emu10k1_capture_efx_ops
|
|
|
|
*/
|
2008-10-23 18:51:00 +02:00
|
|
|
static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
|
2005-12-04 18:03:03 +01:00
|
|
|
{
|
2009-02-25 22:28:59 +01:00
|
|
|
u32 tmp, tmp2, reg;
|
2006-10-01 10:48:04 +01:00
|
|
|
int err;
|
|
|
|
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev, "emu1010: Special config.\n");
|
2023-04-21 16:10:03 +02:00
|
|
|
|
|
|
|
/* Mute, and disable audio and lock cache, just in case.
|
|
|
|
* Proper init follows in snd_emu10k1_init(). */
|
|
|
|
outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
|
2005-12-04 18:03:03 +01:00
|
|
|
|
2024-04-28 11:37:14 +02:00
|
|
|
snd_emu1010_fpga_lock(emu);
|
|
|
|
|
2024-04-28 11:37:14 +02:00
|
|
|
dev_info(emu->card->dev, "emu1010: Loading Hana Firmware\n");
|
2016-11-02 18:13:06 +01:00
|
|
|
err = snd_emu1010_load_firmware(emu, 0, &emu->firmware);
|
|
|
|
if (err < 0) {
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n");
|
2024-04-28 11:37:14 +02:00
|
|
|
goto fail;
|
2005-12-04 18:03:03 +01:00
|
|
|
}
|
2006-10-01 10:48:04 +01:00
|
|
|
|
|
|
|
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®);
|
2007-07-14 10:24:49 +01:00
|
|
|
if ((reg & 0x3f) != 0x15) {
|
2006-10-01 10:48:04 +01:00
|
|
|
/* FPGA failed to be programmed */
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev,
|
|
|
|
"emu1010: Loading Hana Firmware file failed, reg = 0x%x\n",
|
|
|
|
reg);
|
2024-04-28 11:37:14 +02:00
|
|
|
err = -ENODEV;
|
|
|
|
goto fail;
|
2005-12-04 18:03:03 +01:00
|
|
|
}
|
|
|
|
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n");
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp);
|
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2);
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev, "emu1010: Hana version: %u.%u\n", tmp, tmp2);
|
2006-10-01 10:48:04 +01:00
|
|
|
/* Enable 48Volt power to Audio Dock */
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON);
|
2006-10-01 10:48:04 +01:00
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®);
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg);
|
2023-07-10 08:59:55 +02:00
|
|
|
if (reg & EMU_HANA_OPTION_DOCK_OFFLINE)
|
2024-04-28 11:37:12 +02:00
|
|
|
snd_emu1010_load_dock_firmware(emu);
|
2023-05-16 11:36:11 +02:00
|
|
|
if (emu->card_capabilities->no_adat) {
|
|
|
|
emu->emu1010.optical_in = 0; /* IN_SPDIF */
|
|
|
|
emu->emu1010.optical_out = 0; /* OUT_SPDIF */
|
|
|
|
} else {
|
|
|
|
/* Optical -> ADAT I/O */
|
|
|
|
emu->emu1010.optical_in = 1; /* IN_ADAT */
|
|
|
|
emu->emu1010.optical_out = 1; /* OUT_ADAT */
|
|
|
|
}
|
2023-04-28 10:07:32 +02:00
|
|
|
tmp = (emu->emu1010.optical_in ? EMU_HANA_OPTICAL_IN_ADAT : EMU_HANA_OPTICAL_IN_SPDIF) |
|
|
|
|
(emu->emu1010.optical_out ? EMU_HANA_OPTICAL_OUT_ADAT : EMU_HANA_OPTICAL_OUT_SPDIF);
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_OPTICAL_TYPE, tmp);
|
2006-10-01 10:48:04 +01:00
|
|
|
/* Set no attenuation on Audio Dock pads. */
|
2006-10-09 23:08:00 +01:00
|
|
|
emu->emu1010.adc_pads = 0x00;
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_ADC_PADS, emu->emu1010.adc_pads);
|
2006-10-01 10:48:04 +01:00
|
|
|
/* Unmute Audio dock DACs, Headphone source DAC-4. */
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_MISC, EMU_HANA_DOCK_PHONES_192_DAC4);
|
2006-10-09 23:08:00 +01:00
|
|
|
/* DAC PADs. */
|
2023-04-28 10:07:32 +02:00
|
|
|
emu->emu1010.dac_pads = EMU_HANA_DOCK_DAC_PAD1 | EMU_HANA_DOCK_DAC_PAD2 |
|
|
|
|
EMU_HANA_DOCK_DAC_PAD3 | EMU_HANA_DOCK_DAC_PAD4;
|
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_DAC_PADS, emu->emu1010.dac_pads);
|
2006-10-01 10:48:04 +01:00
|
|
|
/* SPDIF Format. Set Consumer mode, 24bit, copy enable */
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, EMU_HANA_SPDIF_MODE_RX_INVALID);
|
2006-10-01 10:48:04 +01:00
|
|
|
/* MIDI routing */
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_IN, EMU_HANA_MIDI_INA_FROM_HAMOA | EMU_HANA_MIDI_INB_FROM_DOCK2);
|
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_MIDI_OUT, EMU_HANA_MIDI_OUT_DOCK2 | EMU_HANA_MIDI_OUT_SYNC2);
|
2023-07-10 08:59:55 +02:00
|
|
|
|
|
|
|
emu->gpio_interrupt = emu1010_interrupt;
|
|
|
|
// Note: The Audigy INTE is set later
|
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE,
|
2023-07-15 18:07:38 +02:00
|
|
|
EMU_HANA_IRQ_DOCK | EMU_HANA_IRQ_DOCK_LOST | EMU_HANA_IRQ_WCLK_CHANGED);
|
2023-07-10 08:59:55 +02:00
|
|
|
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); // Clear pending IRQs
|
2006-10-01 10:48:04 +01:00
|
|
|
|
2023-06-12 21:13:17 +02:00
|
|
|
emu->emu1010.clock_source = 1; /* 48000 */
|
|
|
|
emu->emu1010.clock_fallback = 1; /* 48000 */
|
2006-10-01 10:48:04 +01:00
|
|
|
/* Default WCLK set to 48kHz. */
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, EMU_HANA_DEFCLOCK_48K);
|
2006-10-01 10:48:04 +01:00
|
|
|
/* Word Clock source, Internal 48kHz x1 */
|
2023-06-12 21:13:18 +02:00
|
|
|
emu->emu1010.wclock = EMU_HANA_WCLOCK_INT_48K;
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K);
|
|
|
|
/* snd_emu1010_fpga_write(emu, EMU_HANA_WCLOCK, EMU_HANA_WCLOCK_INT_48K | EMU_HANA_WCLOCK_4X); */
|
2023-06-12 21:13:18 +02:00
|
|
|
snd_emu1010_update_clock(emu);
|
2005-12-04 18:03:03 +01:00
|
|
|
|
ALSA: emu10k1: make E-MU I/O routing init data-driven
... and move it to the mixer init, as it's logically part of it.
As a side effect, this fixes the initial values of the input destination
mixer controls, which would have previously remained at "Silent" despite
different defaults. This didn't really matter, though, as ALSA state
restoration would hide that bug beyond first use.
Note that this completely does away with clearing the output routing
registers, as it was rather pointless - we just programmed the FPGA
(resetting it first if necessary), so everything is zeroed anyway
(that's documented by Xilinx, and as further evidence, some of the loops
terminated too early, and we didn't bother clearing the high channels of
the input routes at all, all with no observed adverse effects).
As a drive-by, this also fixes some capture channel defaults - any
EMU_SRC_*2 isn't a sensible value in 1x clock mode.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Link: https://lore.kernel.org/r/20230516093612.3536508-7-oswald.buddenhagen@gmx.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2023-05-16 11:36:08 +02:00
|
|
|
// The routes are all set to EMU_SRC_SILENCE due to the reset,
|
|
|
|
// so it is safe to simply enable the outputs.
|
2023-04-28 10:07:32 +02:00
|
|
|
snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE);
|
2008-10-23 18:51:00 +02:00
|
|
|
|
2024-04-28 11:37:14 +02:00
|
|
|
fail:
|
|
|
|
snd_emu1010_fpga_unlock(emu);
|
|
|
|
return err;
|
2005-12-04 18:03:03 +01:00
|
|
|
}
|
2005-04-16 15:20:36 -07:00
|
|
|
/*
|
|
|
|
* Create the EMU10K1 instance
|
|
|
|
*/
|
|
|
|
|
2012-08-14 18:12:04 +02:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2005-11-17 16:14:10 +01:00
|
|
|
static int alloc_pm_buffer(struct snd_emu10k1 *emu);
|
|
|
|
static void free_pm_buffer(struct snd_emu10k1 *emu);
|
|
|
|
#endif
|
|
|
|
|
2021-07-15 09:58:55 +02:00
|
|
|
static void snd_emu10k1_free(struct snd_card *card)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
2021-07-15 09:58:55 +02:00
|
|
|
struct snd_emu10k1 *emu = card->private_data;
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
if (emu->port) { /* avoid access to already used hardware */
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu10k1_fx8010_tram_setup(emu, 0);
|
2005-04-16 15:20:36 -07:00
|
|
|
snd_emu10k1_done(emu);
|
2005-11-17 16:14:10 +01:00
|
|
|
snd_emu10k1_free_efx(emu);
|
2008-10-23 18:51:00 +02:00
|
|
|
}
|
2007-12-21 16:33:32 +01:00
|
|
|
if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1010) {
|
2006-10-01 10:48:04 +01:00
|
|
|
/* Disable 48Volt power to Audio Dock */
|
2024-04-28 11:37:14 +02:00
|
|
|
snd_emu1010_fpga_write_lock(emu, EMU_HANA_DOCK_PWR, 0);
|
2006-10-01 10:48:04 +01:00
|
|
|
}
|
2024-04-28 11:37:13 +02:00
|
|
|
cancel_work_sync(&emu->emu1010.work);
|
2024-04-28 11:37:14 +02:00
|
|
|
mutex_destroy(&emu->emu1010.lock);
|
2014-11-03 14:54:36 +01:00
|
|
|
release_firmware(emu->firmware);
|
|
|
|
release_firmware(emu->dock_fw);
|
|
|
|
snd_util_memhdr_free(emu->memhdr);
|
2005-04-16 15:20:36 -07:00
|
|
|
if (emu->silent_page.area)
|
|
|
|
snd_dma_free_pages(&emu->silent_page);
|
|
|
|
if (emu->ptb_pages.area)
|
|
|
|
snd_dma_free_pages(&emu->ptb_pages);
|
|
|
|
vfree(emu->page_ptr_table);
|
|
|
|
vfree(emu->page_addr_table);
|
2012-08-14 18:12:04 +02:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2005-11-17 16:14:10 +01:00
|
|
|
free_pm_buffer(emu);
|
|
|
|
#endif
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2020-01-03 09:17:10 +01:00
|
|
|
static const struct snd_emu_chip_details emu_chip_details[] = {
|
2015-03-28 19:20:35 +01:00
|
|
|
/* Audigy 5/Rx SB1550 */
|
|
|
|
/* Tested by michael@gernoth.net 28 Mar 2015 */
|
|
|
|
/* DSP: CA10300-IAT LF
|
|
|
|
* DAC: Cirrus Logic CS4382-KQZ
|
|
|
|
* ADC: Philips 1361T
|
|
|
|
* AC97: Sigmatel STAC9750
|
|
|
|
* CA0151: None
|
|
|
|
*/
|
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10241102,
|
|
|
|
.driver = "Audigy2", .name = "SB Audigy 5/Rx [SB1550]",
|
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
|
|
|
|
.ac97_chip = 1},
|
2006-04-09 17:36:39 +01:00
|
|
|
/* Audigy4 (Not PRO) SB0610 */
|
|
|
|
/* Tested by James@superbug.co.uk 4th April 2006 */
|
|
|
|
/* A_IOCFG bits
|
|
|
|
* Output
|
|
|
|
* 0: ?
|
|
|
|
* 1: ?
|
|
|
|
* 2: ?
|
|
|
|
* 3: 0 - Digital Out, 1 - Line in
|
|
|
|
* 4: ?
|
|
|
|
* 5: ?
|
|
|
|
* 6: ?
|
|
|
|
* 7: ?
|
|
|
|
* Input
|
|
|
|
* 8: ?
|
|
|
|
* 9: ?
|
|
|
|
* A: Green jack sense (Front)
|
|
|
|
* B: ?
|
|
|
|
* C: Black jack sense (Rear/Side Right)
|
|
|
|
* D: Yellow jack sense (Center/LFE/Side Left)
|
|
|
|
* E: ?
|
|
|
|
* F: ?
|
|
|
|
*
|
|
|
|
* Digital Out/Line in switch using A_IOCFG bit 3 (0x08)
|
|
|
|
* 0 - Digital Out
|
|
|
|
* 1 - Line in
|
|
|
|
*/
|
|
|
|
/* Mic input not tested.
|
|
|
|
* Analog CD input not tested
|
|
|
|
* Digital Out not tested.
|
|
|
|
* Line in working.
|
|
|
|
* Audio output 5.1 working. Side outputs not working.
|
|
|
|
*/
|
|
|
|
/* DSP: CA10300-IAT LF
|
|
|
|
* DAC: Cirrus Logic CS4382-KQZ
|
|
|
|
* ADC: Philips 1361T
|
|
|
|
* AC97: Sigmatel STAC9750
|
|
|
|
* CA0151: None
|
|
|
|
*/
|
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10211102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 4 [SB0610]",
|
2006-04-09 17:36:39 +01:00
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
|
|
|
|
.ac97_chip = 1} ,
|
2008-10-21 17:42:54 +02:00
|
|
|
/* Audigy 2 Value AC3 out does not work yet.
|
|
|
|
* Need to find out how to turn off interpolators.
|
|
|
|
*/
|
|
|
|
/* Tested by James@superbug.co.uk 3rd July 2005 */
|
|
|
|
/* DSP: CA0108-IAT
|
|
|
|
* DAC: CS4382-KQ
|
|
|
|
* ADC: Philips 1361T
|
|
|
|
* AC97: STAC9750
|
|
|
|
* CA0151: None
|
|
|
|
*/
|
2023-04-22 18:10:15 +02:00
|
|
|
/*
|
|
|
|
* A_IOCFG Input (GPIO)
|
|
|
|
* 0x400 = Front analog jack plugged in. (Green socket)
|
|
|
|
* 0x1000 = Rear analog jack plugged in. (Black socket)
|
|
|
|
* 0x2000 = Center/LFE analog jack plugged in. (Orange socket)
|
|
|
|
* A_IOCFG Output (GPIO)
|
|
|
|
* 0x60 = Sound out of front Left.
|
|
|
|
* Win sets it to 0xXX61
|
|
|
|
*/
|
2008-10-21 17:42:54 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x10011102,
|
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 Value [SB0400]",
|
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.ac97_chip = 1} ,
|
2005-10-31 10:27:41 +00:00
|
|
|
/* Audigy 2 ZS Notebook Cardbus card.*/
|
2006-12-06 15:58:02 +00:00
|
|
|
/* Tested by James@superbug.co.uk 6th November 2006 */
|
2005-12-22 13:05:23 +01:00
|
|
|
/* Audio output 7.1/Headphones working.
|
|
|
|
* Digital output working. (AC3 not checked, only PCM)
|
2006-12-06 15:58:02 +00:00
|
|
|
* Audio Mic/Line inputs working.
|
|
|
|
* Digital input not tested.
|
2008-10-21 17:42:54 +02:00
|
|
|
*/
|
2006-04-09 17:36:39 +01:00
|
|
|
/* DSP: Tina2
|
2005-12-22 13:05:23 +01:00
|
|
|
* DAC: Wolfson WM8768/WM8568
|
|
|
|
* ADC: Wolfson WM8775
|
|
|
|
* AC97: None
|
|
|
|
* CA0151: None
|
|
|
|
*/
|
2006-12-06 15:58:02 +00:00
|
|
|
/* Tested by James@superbug.co.uk 4th April 2006 */
|
|
|
|
/* A_IOCFG bits
|
|
|
|
* Output
|
|
|
|
* 0: Not Used
|
|
|
|
* 1: 0 = Mute all the 7.1 channel out. 1 = unmute.
|
|
|
|
* 2: Analog input 0 = line in, 1 = mic in
|
|
|
|
* 3: Not Used
|
|
|
|
* 4: Digital output 0 = off, 1 = on.
|
|
|
|
* 5: Not Used
|
|
|
|
* 6: Not Used
|
|
|
|
* 7: Not Used
|
|
|
|
* Input
|
|
|
|
* All bits 1 (0x3fxx) means nothing plugged in.
|
|
|
|
* 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing.
|
|
|
|
* A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing.
|
|
|
|
* C-D: 2 = Front/Rear/etc, 3 = nothing.
|
|
|
|
* E-F: Always 0
|
|
|
|
*
|
|
|
|
*/
|
2005-10-31 10:27:41 +00:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102,
|
2015-04-27 13:00:09 +02:00
|
|
|
.driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]",
|
2005-10-31 10:27:41 +00:00
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
|
|
|
.ca_cardbus_chip = 1,
|
2005-12-21 15:06:08 +01:00
|
|
|
.spi_dac = 1,
|
2006-12-06 15:58:02 +00:00
|
|
|
.i2c_adc = 1,
|
2005-10-31 10:27:41 +00:00
|
|
|
.spk71 = 1} ,
|
2023-04-22 18:10:15 +02:00
|
|
|
/* This is MAEM8950 "Mana" */
|
|
|
|
/* Attach MicroDock[M] to make it an E-MU 1616[m]. */
|
|
|
|
/* Does NOT support sync daughter card (obviously). */
|
2007-11-04 14:08:26 +00:00
|
|
|
/* Tested by James@superbug.co.uk 4th Nov 2007. */
|
2007-04-19 11:14:41 +01:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x42011102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 02 CardBus [MAEM8950]",
|
2007-04-19 11:14:41 +01:00
|
|
|
.id = "EMU1010",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
|
|
|
.ca_cardbus_chip = 1,
|
2007-07-14 10:24:49 +01:00
|
|
|
.spk71 = 1 ,
|
2007-12-21 16:33:32 +01:00
|
|
|
.emu_model = EMU_MODEL_EMU1616},
|
2007-11-04 14:08:26 +00:00
|
|
|
/* Tested by James@superbug.co.uk 4th Nov 2007. */
|
2023-04-22 18:10:15 +02:00
|
|
|
/* This is MAEM8960 "Hana3", 0202 is MAEM8980 */
|
|
|
|
/* Attach 0202 daughter card to make it an E-MU 1212m, OR a
|
|
|
|
* MicroDock[M] to make it an E-MU 1616[m]. */
|
|
|
|
/* Does NOT support sync daughter card. */
|
2007-07-14 02:18:26 +01:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 1010b PCI [MAEM8960]",
|
2007-07-14 02:18:26 +01:00
|
|
|
.id = "EMU1010",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
2007-11-04 14:08:26 +00:00
|
|
|
.spk71 = 1,
|
2008-10-21 17:42:54 +02:00
|
|
|
.emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 new revision */
|
2012-10-17 18:18:10 +02:00
|
|
|
/* Tested by Maxim Kachur <mcdebugger@duganet.ru> 17th Oct 2012. */
|
|
|
|
/* This is MAEM8986, 0202 is MAEM8980 */
|
2023-04-22 18:10:15 +02:00
|
|
|
/* Attach 0202 daughter card to make it an E-MU 1212m, OR a
|
|
|
|
* MicroDockM to make it an E-MU 1616m. The non-m
|
|
|
|
* version was never sold with this card, but should
|
|
|
|
* still work. */
|
|
|
|
/* Does NOT support sync daughter card. */
|
2012-10-17 18:18:10 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40071102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 1010 PCIe [MAEM8986]",
|
2012-10-17 18:18:10 +02:00
|
|
|
.id = "EMU1010",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.emu_model = EMU_MODEL_EMU1010B}, /* EMU 1010 PCIe */
|
2007-11-04 14:08:26 +00:00
|
|
|
/* Tested by James@superbug.co.uk 8th July 2005. */
|
2023-04-22 18:10:15 +02:00
|
|
|
/* This is MAEM8810 "Hana", 0202 is MAEM8820 "Hamoa" */
|
|
|
|
/* Attach 0202 daughter card to make it an E-MU 1212m, OR an
|
|
|
|
* AudioDock[M] to make it an E-MU 1820[m]. */
|
|
|
|
/* Supports sync daughter card. */
|
2007-11-04 14:08:26 +00:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40011102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 1010 [MAEM8810]",
|
2007-11-04 14:08:26 +00:00
|
|
|
.id = "EMU1010",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.spk71 = 1,
|
2008-10-21 17:42:54 +02:00
|
|
|
.emu_model = EMU_MODEL_EMU1010}, /* EMU 1010 old revision */
|
2023-04-22 18:10:15 +02:00
|
|
|
/* This is MAEM8852 "HanaLiteLite" */
|
|
|
|
/* Supports sync daughter card. */
|
|
|
|
/* Tested by oswald.buddenhagen@gmx.de Mar 2023. */
|
2008-01-07 12:36:56 +01:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40021102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 0404b PCI [MAEM8852]",
|
2008-01-07 12:36:56 +01:00
|
|
|
.id = "EMU0404",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
2023-05-16 11:36:11 +02:00
|
|
|
.spk20 = 1,
|
|
|
|
.no_adat = 1,
|
2008-10-21 17:42:54 +02:00
|
|
|
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 new revision */
|
2023-04-22 18:10:15 +02:00
|
|
|
/* This is MAEM8850 "HanaLite" */
|
|
|
|
/* Supports sync daughter card. */
|
2008-01-07 12:36:56 +01:00
|
|
|
/* Tested by James@superbug.co.uk 20-3-2007. */
|
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x40021102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 0404 [MAEM8850]",
|
2008-01-07 12:36:56 +01:00
|
|
|
.id = "EMU0404",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
2023-05-16 11:36:11 +02:00
|
|
|
.spk20 = 1,
|
|
|
|
.no_adat = 1,
|
2008-01-07 12:36:56 +01:00
|
|
|
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 */
|
2011-06-12 01:15:42 +02:00
|
|
|
/* EMU0404 PCIe */
|
2023-04-22 18:10:15 +02:00
|
|
|
/* Does NOT support sync daughter card. */
|
2011-06-12 01:15:42 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40051102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "Audigy2", .name = "E-MU 0404 PCIe [MAEM8984]",
|
2011-06-12 01:15:42 +02:00
|
|
|
.id = "EMU0404",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0108_chip = 1,
|
2023-05-16 11:36:11 +02:00
|
|
|
.spk20 = 1,
|
|
|
|
.no_adat = 1,
|
2011-06-12 01:15:42 +02:00
|
|
|
.emu_model = EMU_MODEL_EMU0404}, /* EMU 0404 PCIe ver_03 */
|
2008-10-21 17:42:54 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0008,
|
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 Value [Unknown]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
2005-04-01 11:15:07 +02:00
|
|
|
.ca0108_chip = 1,
|
|
|
|
.ac97_chip = 1} ,
|
2005-07-03 12:54:29 +02:00
|
|
|
/* Tested by James@superbug.co.uk 3rd July 2005 */
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20071102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 4 PRO [SB0380]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
|
|
|
.ac97_chip = 1} ,
|
2005-11-07 14:59:19 +01:00
|
|
|
/* Tested by shane-alsa@cm.nu 5th Nov 2005 */
|
2006-04-09 22:45:58 +02:00
|
|
|
/* The 0x20061102 does have SB0350 written on it
|
|
|
|
* Just like 0x20021102
|
|
|
|
*/
|
2005-11-07 14:59:19 +01:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20061102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 [SB0350b]",
|
2005-11-07 14:59:19 +01:00
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
2008-11-03 10:21:36 +01:00
|
|
|
.invert_shared_spdif = 1, /* digital/analog switch swapped */
|
2005-11-07 14:59:19 +01:00
|
|
|
.ac97_chip = 1} ,
|
2011-12-29 18:50:56 +00:00
|
|
|
/* 0x20051102 also has SB0350 written on it, treated as Audigy 2 ZS by
|
|
|
|
Creative's Windows driver */
|
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20051102,
|
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350a]",
|
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
|
|
|
.invert_shared_spdif = 1, /* digital/analog switch swapped */
|
|
|
|
.ac97_chip = 1} ,
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20021102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0350]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
2008-11-03 10:21:36 +01:00
|
|
|
.invert_shared_spdif = 1, /* digital/analog switch swapped */
|
2005-04-16 15:20:36 -07:00
|
|
|
.ac97_chip = 1} ,
|
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x20011102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0360]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
2008-11-03 10:21:36 +01:00
|
|
|
.invert_shared_spdif = 1, /* digital/analog switch swapped */
|
2005-04-16 15:20:36 -07:00
|
|
|
.ac97_chip = 1} ,
|
2005-12-22 12:58:41 +01:00
|
|
|
/* Audigy 2 */
|
|
|
|
/* Tested by James@superbug.co.uk 3rd July 2005 */
|
|
|
|
/* DSP: CA0102-IAT
|
|
|
|
* DAC: CS4382-KQ
|
|
|
|
* ADC: Philips 1361T
|
|
|
|
* AC97: STAC9721
|
|
|
|
* CA0151: Yes
|
|
|
|
*/
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10071102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 [SB0240]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
2006-07-08 16:39:30 +01:00
|
|
|
.adc_1361t = 1, /* 24 bit capture instead of 16bit */
|
2005-04-16 15:20:36 -07:00
|
|
|
.ac97_chip = 1} ,
|
2023-04-22 18:10:15 +02:00
|
|
|
/* Audigy 2 Platinum EX */
|
|
|
|
/* Win driver sets A_IOCFG output to 0x1c00 */
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10051102,
|
2015-04-27 13:00:09 +02:00
|
|
|
.driver = "Audigy2", .name = "Audigy 2 Platinum EX [SB0280]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
2005-11-07 14:54:24 +01:00
|
|
|
.spk71 = 1,
|
2005-04-16 15:20:36 -07:00
|
|
|
.spdif_bug = 1} ,
|
2006-07-30 17:17:59 +01:00
|
|
|
/* Dell OEM/Creative Labs Audigy 2 ZS */
|
|
|
|
/* See ALSA bug#1365 */
|
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10031102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 ZS [SB0353]",
|
2006-07-30 17:17:59 +01:00
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
2009-02-24 15:31:02 +01:00
|
|
|
.invert_shared_spdif = 1, /* digital/analog switch swapped */
|
2006-07-30 17:17:59 +01:00
|
|
|
.ac97_chip = 1} ,
|
2023-04-22 18:10:15 +02:00
|
|
|
/* Audigy 2 Platinum */
|
|
|
|
/* Win driver sets A_IOCFG output to 0xa00 */
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy2",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spk71 = 1,
|
|
|
|
.spdif_bug = 1,
|
2008-06-02 11:45:53 +02:00
|
|
|
.invert_shared_spdif = 1, /* digital/analog switch swapped */
|
2006-11-25 22:02:47 +00:00
|
|
|
.adc_1361t = 1, /* 24 bit capture instead of 16bit. Fixes ALSA bug#324 */
|
2005-04-16 15:20:36 -07:00
|
|
|
.ac97_chip = 1} ,
|
2005-04-07 15:48:42 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .revision = 0x04,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy2", .name = "SB Audigy 2 [Unknown]",
|
2005-04-07 15:48:42 +02:00
|
|
|
.id = "Audigy2",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ca0151_chip = 1,
|
|
|
|
.spdif_bug = 1,
|
|
|
|
.ac97_chip = 1} ,
|
2005-07-06 22:36:18 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00531102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy", .name = "SB Audigy 1 [SB0092]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy",
|
2005-03-27 15:00:54 +02:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
2005-04-01 11:15:07 +02:00
|
|
|
.ac97_chip = 1} ,
|
2005-07-06 22:36:18 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00521102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy", .name = "SB Audigy 1 ES [SB0160]",
|
2005-04-01 11:15:07 +02:00
|
|
|
.id = "Audigy",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
2005-07-06 22:36:18 +02:00
|
|
|
.spdif_bug = 1,
|
2005-04-01 11:15:07 +02:00
|
|
|
.ac97_chip = 1} ,
|
2005-05-27 12:31:34 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0004, .subsystem = 0x00511102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy", .name = "SB Audigy 1 [SB0090]",
|
2005-05-27 12:31:34 +02:00
|
|
|
.id = "Audigy",
|
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
|
|
|
.ac97_chip = 1} ,
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0004,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "Audigy", .name = "Audigy 1 [Unknown]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Audigy",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k2_chip = 1,
|
|
|
|
.ca0102_chip = 1,
|
2005-04-01 11:15:07 +02:00
|
|
|
.ac97_chip = 1} ,
|
2008-10-21 17:42:54 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x100a1102,
|
|
|
|
.driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]",
|
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806b1102,
|
|
|
|
.driver = "EMU10K1", .name = "SB Live! [SB0105]",
|
2005-05-11 11:13:26 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2008-10-21 17:42:54 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x806a1102,
|
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [SB0103]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Live",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k1_chip = 1,
|
2005-03-30 13:51:18 +02:00
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80691102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [SB0101]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-12-26 15:30:03 +01:00
|
|
|
/* Tested by ALSA bug#1680 26th December 2005 */
|
2008-10-21 17:42:54 +02:00
|
|
|
/* note: It really has SB0220 written on the card, */
|
|
|
|
/* but it's SB0228 according to kx.inf */
|
2005-12-26 15:30:03 +01:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80661102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! 5.1 Dell OEM [SB0228]",
|
2005-12-26 15:30:03 +01:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-08-29 17:42:00 +02:00
|
|
|
/* Tested by Thomas Zehetbauer 27th Aug 2005 */
|
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80651102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! 5.1 [SB0220]",
|
2005-12-06 14:10:57 +01:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80641102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! 5.1",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-09-10 10:24:10 +02:00
|
|
|
/* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! 5.1 [SB0060]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
2005-09-30 16:56:59 +02:00
|
|
|
.ac97_chip = 2, /* ac97 is optional; both SBLive 5.1 and platinum
|
|
|
|
* share the same IDs!
|
|
|
|
*/
|
2005-06-18 13:50:22 +02:00
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4850]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2023-04-22 18:10:15 +02:00
|
|
|
/* SB Live! Platinum */
|
|
|
|
/* Win driver sets A_IOCFG output to 0 */
|
|
|
|
/* Tested by Jonathan Dowland <jon@dow.land> Apr 2023. */
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80401102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Platinum [CT4760P]",
|
2005-07-03 12:32:40 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1} ,
|
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80321102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4871]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80311102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4831]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80281102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4870]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Live",
|
2005-03-30 13:51:18 +02:00
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:54:29 +02:00
|
|
|
/* Tested by James@superbug.co.uk 3rd July 2005 */
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80271102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4832]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80261102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4830]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80231102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB PCI512 [CT4790]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80221102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4780]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x40011102,
|
2023-04-28 11:59:41 +02:00
|
|
|
.driver = "EMU10K1", .name = "E-MU APS [PC545]",
|
2005-07-03 12:32:40 +02:00
|
|
|
.id = "APS",
|
2005-06-18 13:50:22 +02:00
|
|
|
.emu10k1_chip = 1,
|
2005-07-03 12:32:40 +02:00
|
|
|
.ecard = 1} ,
|
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00211102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! [CT4620]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-07-03 12:32:40 +02:00
|
|
|
{.vendor = 0x1102, .device = 0x0002, .subsystem = 0x00201102,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! Value [CT4670]",
|
2005-06-18 13:50:22 +02:00
|
|
|
.id = "Live",
|
|
|
|
.emu10k1_chip = 1,
|
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-04-16 15:20:36 -07:00
|
|
|
{.vendor = 0x1102, .device = 0x0002,
|
2008-10-21 17:42:54 +02:00
|
|
|
.driver = "EMU10K1", .name = "SB Live! [Unknown]",
|
2005-03-30 14:22:25 +02:00
|
|
|
.id = "Live",
|
2005-04-16 15:20:36 -07:00
|
|
|
.emu10k1_chip = 1,
|
2005-03-30 13:51:18 +02:00
|
|
|
.ac97_chip = 1,
|
|
|
|
.sblive51 = 1} ,
|
2005-04-16 15:20:36 -07:00
|
|
|
{ } /* terminator */
|
|
|
|
};
|
|
|
|
|
2018-02-14 00:07:58 +01:00
|
|
|
/*
|
|
|
|
* The chip (at least the Audigy 2 CA0102 chip, but most likely others, too)
|
|
|
|
* has a problem that from time to time it likes to do few DMA reads a bit
|
|
|
|
* beyond its normal allocation and gets very confused if these reads get
|
|
|
|
* blocked by a IOMMU.
|
|
|
|
*
|
|
|
|
* This behaviour has been observed for the first (reserved) page
|
|
|
|
* (for which it happens multiple times at every playback), often for various
|
|
|
|
* synth pages and sometimes for PCM playback buffers and the page table
|
|
|
|
* memory itself.
|
|
|
|
*
|
|
|
|
* As a workaround let's widen these DMA allocations by an extra page if we
|
|
|
|
* detect that the device is behind a non-passthrough IOMMU.
|
|
|
|
*/
|
|
|
|
static void snd_emu10k1_detect_iommu(struct snd_emu10k1 *emu)
|
|
|
|
{
|
|
|
|
struct iommu_domain *domain;
|
|
|
|
|
|
|
|
emu->iommu_workaround = false;
|
|
|
|
|
|
|
|
domain = iommu_get_domain_for_dev(emu->card->dev);
|
2022-04-05 14:27:54 +01:00
|
|
|
if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY)
|
2018-02-14 00:07:58 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
dev_notice(emu->card->dev,
|
|
|
|
"non-passthrough IOMMU detected, widening DMA allocations");
|
|
|
|
emu->iommu_workaround = true;
|
|
|
|
}
|
|
|
|
|
2012-12-06 12:35:10 -05:00
|
|
|
int snd_emu10k1_create(struct snd_card *card,
|
2008-10-23 18:51:00 +02:00
|
|
|
struct pci_dev *pci,
|
2005-04-16 15:20:36 -07:00
|
|
|
unsigned short extin_mask,
|
|
|
|
unsigned short extout_mask,
|
|
|
|
long max_cache_bytes,
|
|
|
|
int enable_ir,
|
2021-07-15 09:58:55 +02:00
|
|
|
uint subsystem)
|
2005-04-16 15:20:36 -07:00
|
|
|
{
|
2021-07-15 09:58:55 +02:00
|
|
|
struct snd_emu10k1 *emu = card->private_data;
|
2005-11-17 16:14:10 +01:00
|
|
|
int idx, err;
|
2005-04-16 15:20:36 -07:00
|
|
|
int is_audigy;
|
2018-02-14 00:07:58 +01:00
|
|
|
size_t page_table_size;
|
2020-02-06 17:31:51 +01:00
|
|
|
__le32 *pgtbl;
|
2005-11-17 16:14:10 +01:00
|
|
|
unsigned int silent_page;
|
2005-11-17 14:50:13 +01:00
|
|
|
const struct snd_emu_chip_details *c;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
/* enable PCI device */
|
2021-07-15 09:58:55 +02:00
|
|
|
err = pcim_enable_device(pci);
|
2008-10-23 18:51:00 +02:00
|
|
|
if (err < 0)
|
2005-04-16 15:20:36 -07:00
|
|
|
return err;
|
|
|
|
|
2021-07-15 09:58:55 +02:00
|
|
|
card->private_free = snd_emu10k1_free;
|
2005-04-16 15:20:36 -07:00
|
|
|
emu->card = card;
|
|
|
|
spin_lock_init(&emu->reg_lock);
|
|
|
|
spin_lock_init(&emu->emu_lock);
|
2007-11-10 17:55:14 +00:00
|
|
|
spin_lock_init(&emu->spi_lock);
|
|
|
|
spin_lock_init(&emu->i2c_lock);
|
2005-04-16 15:20:36 -07:00
|
|
|
spin_lock_init(&emu->voice_lock);
|
|
|
|
spin_lock_init(&emu->synth_lock);
|
|
|
|
spin_lock_init(&emu->memblk_lock);
|
2006-01-16 16:34:20 +01:00
|
|
|
mutex_init(&emu->fx8010.lock);
|
2005-04-16 15:20:36 -07:00
|
|
|
INIT_LIST_HEAD(&emu->mapped_link_head);
|
|
|
|
INIT_LIST_HEAD(&emu->mapped_order_link_head);
|
|
|
|
emu->pci = pci;
|
|
|
|
emu->irq = -1;
|
|
|
|
emu->synth = NULL;
|
|
|
|
emu->get_synth_voice = NULL;
|
2024-04-28 11:37:13 +02:00
|
|
|
INIT_WORK(&emu->emu1010.work, emu1010_work);
|
2024-04-28 11:37:14 +02:00
|
|
|
mutex_init(&emu->emu1010.lock);
|
2005-04-16 15:20:36 -07:00
|
|
|
/* read revision & serial */
|
2007-06-08 15:46:36 -07:00
|
|
|
emu->revision = pci->revision;
|
2005-04-16 15:20:36 -07:00
|
|
|
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
|
|
|
|
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_dbg(card->dev,
|
|
|
|
"vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n",
|
|
|
|
pci->vendor, pci->device, emu->serial, emu->model);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
for (c = emu_chip_details; c->vendor; c++) {
|
|
|
|
if (c->vendor == pci->vendor && c->device == pci->device) {
|
2005-07-06 22:21:51 +02:00
|
|
|
if (subsystem) {
|
2008-10-23 18:51:00 +02:00
|
|
|
if (c->subsystem && (c->subsystem == subsystem))
|
2005-07-06 22:21:51 +02:00
|
|
|
break;
|
2008-10-23 18:51:00 +02:00
|
|
|
else
|
|
|
|
continue;
|
2005-07-06 22:21:51 +02:00
|
|
|
} else {
|
2008-10-23 18:51:00 +02:00
|
|
|
if (c->subsystem && (c->subsystem != emu->serial))
|
2005-07-06 22:21:51 +02:00
|
|
|
continue;
|
|
|
|
if (c->revision && c->revision != emu->revision)
|
|
|
|
continue;
|
|
|
|
}
|
2005-04-07 15:48:42 +02:00
|
|
|
break;
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (c->vendor == 0) {
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_err(card->dev, "emu10k1: Card not recognised\n");
|
2005-04-16 15:20:36 -07:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
emu->card_capabilities = c;
|
2005-07-06 22:21:51 +02:00
|
|
|
if (c->subsystem && !subsystem)
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_dbg(card->dev, "Sound card name = %s\n", c->name);
|
2008-10-23 18:51:00 +02:00
|
|
|
else if (subsystem)
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_dbg(card->dev, "Sound card name = %s, "
|
2008-10-23 18:51:00 +02:00
|
|
|
"vendor = 0x%x, device = 0x%x, subsystem = 0x%x. "
|
2010-03-16 11:47:56 +01:00
|
|
|
"Forced to subsystem = 0x%x\n", c->name,
|
2008-10-23 18:51:00 +02:00
|
|
|
pci->vendor, pci->device, emu->serial, c->subsystem);
|
|
|
|
else
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_dbg(card->dev, "Sound card name = %s, "
|
2008-10-23 18:51:00 +02:00
|
|
|
"vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n",
|
|
|
|
c->name, pci->vendor, pci->device,
|
|
|
|
emu->serial);
|
|
|
|
|
2019-04-16 18:01:46 +02:00
|
|
|
if (!*card->id && c->id)
|
ALSA: Convert strlcpy to strscpy when return value is unused
strlcpy is deprecated. see: Documentation/process/deprecated.rst
Change the calls that do not use the strlcpy return value to the
preferred strscpy.
Done with cocci script:
@@
expression e1, e2, e3;
@@
- strlcpy(
+ strscpy(
e1, e2, e3);
This cocci script leaves the instances where the return value is
used unchanged.
After this patch, sound/ has 3 uses of strlcpy() that need to be
manually inspected for conversion and changed one day.
$ git grep -w strlcpy sound/
sound/usb/card.c: len = strlcpy(card->longname, s, sizeof(card->longname));
sound/usb/mixer.c: return strlcpy(buf, p->name, buflen);
sound/usb/mixer.c: return strlcpy(buf, p->names[index], buflen);
Miscellenea:
o Remove trailing whitespace in conversion of sound/core/hwdep.c
Link: https://lore.kernel.org/lkml/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/
Signed-off-by: Joe Perches <joe@perches.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/22b393d1790bb268769d0bab7bacf0866dcb0c14.camel@perches.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-04 09:17:34 -08:00
|
|
|
strscpy(card->id, c->id, sizeof(card->id));
|
2005-03-30 14:22:25 +02:00
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
is_audigy = emu->audigy = c->emu10k2_chip;
|
|
|
|
|
2018-02-14 00:07:58 +01:00
|
|
|
snd_emu10k1_detect_iommu(emu);
|
|
|
|
|
2015-04-28 21:57:29 +02:00
|
|
|
/* set addressing mode */
|
|
|
|
emu->address_mode = is_audigy ? 0 : 1;
|
2005-04-16 15:20:36 -07:00
|
|
|
/* set the DMA transfer mask */
|
2015-04-28 21:57:29 +02:00
|
|
|
emu->dma_mask = emu->address_mode ? EMU10K1_DMA_MASK : AUDIGY_DMA_MASK;
|
2018-02-14 00:05:16 +01:00
|
|
|
if (dma_set_mask_and_coherent(&pci->dev, emu->dma_mask) < 0) {
|
2014-02-25 17:02:09 +01:00
|
|
|
dev_err(card->dev,
|
|
|
|
"architecture does not support PCI busmaster DMA with mask 0x%lx\n",
|
|
|
|
emu->dma_mask);
|
2005-04-16 15:20:36 -07:00
|
|
|
return -ENXIO;
|
|
|
|
}
|
|
|
|
if (is_audigy)
|
|
|
|
emu->gpr_base = A_FXGPREGBASE;
|
|
|
|
else
|
|
|
|
emu->gpr_base = FXGPREGBASE;
|
|
|
|
|
2008-10-23 18:51:00 +02:00
|
|
|
err = pci_request_regions(pci, "EMU10K1");
|
2021-07-15 09:58:55 +02:00
|
|
|
if (err < 0)
|
2005-04-16 15:20:36 -07:00
|
|
|
return err;
|
|
|
|
emu->port = pci_resource_start(pci, 0);
|
|
|
|
|
|
|
|
emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT;
|
2018-02-14 00:07:58 +01:00
|
|
|
|
|
|
|
page_table_size = sizeof(u32) * (emu->address_mode ? MAXPAGES1 :
|
|
|
|
MAXPAGES0);
|
|
|
|
if (snd_emu10k1_alloc_pages_maybe_wider(emu, page_table_size,
|
2021-07-15 09:58:55 +02:00
|
|
|
&emu->ptb_pages) < 0)
|
|
|
|
return -ENOMEM;
|
2018-02-14 00:06:18 +01:00
|
|
|
dev_dbg(card->dev, "page table address range is %.8lx:%.8lx\n",
|
|
|
|
(unsigned long)emu->ptb_pages.addr,
|
|
|
|
(unsigned long)(emu->ptb_pages.addr + emu->ptb_pages.bytes));
|
2005-04-16 15:20:36 -07:00
|
|
|
|
treewide: Use array_size() in vmalloc()
The vmalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vmalloc(a * b)
with:
vmalloc(array_size(a, b))
as well as handling cases of:
vmalloc(a * b * c)
with:
vmalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vmalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vmalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vmalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vmalloc(C1 * C2 * C3, ...)
|
vmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vmalloc(C1 * C2, ...)
|
vmalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:27:11 -07:00
|
|
|
emu->page_ptr_table = vmalloc(array_size(sizeof(void *),
|
|
|
|
emu->max_cache_pages));
|
|
|
|
emu->page_addr_table = vmalloc(array_size(sizeof(unsigned long),
|
|
|
|
emu->max_cache_pages));
|
2021-07-15 09:58:55 +02:00
|
|
|
if (!emu->page_ptr_table || !emu->page_addr_table)
|
|
|
|
return -ENOMEM;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2018-02-14 00:07:58 +01:00
|
|
|
if (snd_emu10k1_alloc_pages_maybe_wider(emu, EMUPAGESIZE,
|
2021-07-15 09:58:55 +02:00
|
|
|
&emu->silent_page) < 0)
|
|
|
|
return -ENOMEM;
|
2018-02-14 00:06:18 +01:00
|
|
|
dev_dbg(card->dev, "silent page range is %.8lx:%.8lx\n",
|
|
|
|
(unsigned long)emu->silent_page.addr,
|
|
|
|
(unsigned long)(emu->silent_page.addr +
|
|
|
|
emu->silent_page.bytes));
|
|
|
|
|
2005-04-16 15:20:36 -07:00
|
|
|
emu->memhdr = snd_util_memhdr_new(emu->max_cache_pages * PAGE_SIZE);
|
2021-07-15 09:58:55 +02:00
|
|
|
if (!emu->memhdr)
|
|
|
|
return -ENOMEM;
|
2005-11-17 14:50:13 +01:00
|
|
|
emu->memhdr->block_extra_size = sizeof(struct snd_emu10k1_memblk) -
|
|
|
|
sizeof(struct snd_util_memblk);
|
2005-04-16 15:20:36 -07:00
|
|
|
|
|
|
|
pci_set_master(pci);
|
|
|
|
|
2023-04-21 16:10:06 +02:00
|
|
|
// The masks are not used for Audigy.
|
|
|
|
// FIXME: these should come from the card_capabilites table.
|
2005-04-16 15:20:36 -07:00
|
|
|
if (extin_mask == 0)
|
2023-04-21 16:10:06 +02:00
|
|
|
extin_mask = 0x3fcf; // EXTIN_*
|
2005-04-16 15:20:36 -07:00
|
|
|
if (extout_mask == 0)
|
2023-04-21 16:10:06 +02:00
|
|
|
extout_mask = 0x7fff; // EXTOUT_*
|
2005-04-16 15:20:36 -07:00
|
|
|
emu->fx8010.extin_mask = extin_mask;
|
|
|
|
emu->fx8010.extout_mask = extout_mask;
|
2005-11-17 16:14:10 +01:00
|
|
|
emu->enable_ir = enable_ir;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2007-07-14 10:24:49 +01:00
|
|
|
if (emu->card_capabilities->ca_cardbus_chip) {
|
2008-10-23 18:51:00 +02:00
|
|
|
err = snd_emu10k1_cardbus_init(emu);
|
|
|
|
if (err < 0)
|
2021-07-15 09:58:55 +02:00
|
|
|
return err;
|
2007-07-14 10:24:49 +01:00
|
|
|
}
|
2005-03-30 13:51:18 +02:00
|
|
|
if (emu->card_capabilities->ecard) {
|
2008-10-23 18:51:00 +02:00
|
|
|
err = snd_emu10k1_ecard_init(emu);
|
|
|
|
if (err < 0)
|
2021-07-15 09:58:55 +02:00
|
|
|
return err;
|
2007-11-04 14:08:26 +00:00
|
|
|
} else if (emu->card_capabilities->emu_model) {
|
2008-10-23 18:51:00 +02:00
|
|
|
err = snd_emu10k1_emu1010_init(emu);
|
2021-07-15 09:58:55 +02:00
|
|
|
if (err < 0)
|
2008-10-23 18:51:00 +02:00
|
|
|
return err;
|
2005-04-16 15:20:36 -07:00
|
|
|
} else {
|
|
|
|
/* 5.1: Enable the additional AC97 Slots. If the emu10k1 version
|
|
|
|
does not support this, it shouldn't do any harm */
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu10k1_ptr_write(emu, AC97SLOT, 0,
|
|
|
|
AC97SLOT_CNTR|AC97SLOT_LFE);
|
2005-04-16 15:20:36 -07:00
|
|
|
}
|
|
|
|
|
2005-11-17 16:14:10 +01:00
|
|
|
/* initialize TRAM setup */
|
|
|
|
emu->fx8010.itram_size = (16 * 1024)/2;
|
|
|
|
emu->fx8010.etram_pages.area = NULL;
|
|
|
|
emu->fx8010.etram_pages.bytes = 0;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2008-06-06 11:04:19 +02:00
|
|
|
/* irq handler must be registered after I/O ports are activated */
|
2021-07-15 09:58:55 +02:00
|
|
|
if (devm_request_irq(&pci->dev, pci->irq, snd_emu10k1_interrupt,
|
|
|
|
IRQF_SHARED, KBUILD_MODNAME, emu))
|
|
|
|
return -EBUSY;
|
2008-06-06 11:04:19 +02:00
|
|
|
emu->irq = pci->irq;
|
2019-12-10 07:34:15 +01:00
|
|
|
card->sync_irq = emu->irq;
|
2008-06-06 11:04:19 +02:00
|
|
|
|
2005-11-17 16:14:10 +01:00
|
|
|
/*
|
|
|
|
* Init to 0x02109204 :
|
|
|
|
* Clock accuracy = 0 (1000ppm)
|
|
|
|
* Sample Rate = 2 (48kHz)
|
|
|
|
* Audio Channel = 1 (Left of 2)
|
|
|
|
* Source Number = 0 (Unspecified)
|
|
|
|
* Generation Status = 1 (Original for Cat Code 12)
|
|
|
|
* Cat Code = 12 (Digital Signal Mixer)
|
|
|
|
* Mode = 0 (Mode 0)
|
|
|
|
* Emphasis = 0 (None)
|
|
|
|
* CP = 1 (Copyright unasserted)
|
|
|
|
* AN = 0 (Audio data)
|
|
|
|
* P = 0 (Consumer)
|
|
|
|
*/
|
|
|
|
emu->spdif_bits[0] = emu->spdif_bits[1] =
|
|
|
|
emu->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
|
|
|
|
SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC |
|
|
|
|
SPCS_GENERATIONSTATUS | 0x00001200 |
|
|
|
|
0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
|
|
|
|
|
|
|
|
/* Clear silent pages and set up pointers */
|
2018-02-14 00:07:58 +01:00
|
|
|
memset(emu->silent_page.area, 0, emu->silent_page.bytes);
|
2015-04-28 21:57:29 +02:00
|
|
|
silent_page = emu->silent_page.addr << emu->address_mode;
|
2020-02-06 17:31:51 +01:00
|
|
|
pgtbl = (__le32 *)emu->ptb_pages.area;
|
2015-04-28 21:57:29 +02:00
|
|
|
for (idx = 0; idx < (emu->address_mode ? MAXPAGES1 : MAXPAGES0); idx++)
|
2020-02-06 17:31:51 +01:00
|
|
|
pgtbl[idx] = cpu_to_le32(silent_page | idx);
|
2005-11-17 16:14:10 +01:00
|
|
|
|
|
|
|
/* set up voice indices */
|
2023-04-21 16:10:04 +02:00
|
|
|
for (idx = 0; idx < NUM_G; idx++)
|
2005-11-17 16:14:10 +01:00
|
|
|
emu->voices[idx].number = idx;
|
2005-04-16 15:20:36 -07:00
|
|
|
|
2023-04-22 15:24:29 +02:00
|
|
|
err = snd_emu10k1_init(emu, enable_ir);
|
2008-10-23 18:51:00 +02:00
|
|
|
if (err < 0)
|
2021-07-15 09:58:55 +02:00
|
|
|
return err;
|
2012-08-14 18:12:04 +02:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2008-10-23 18:51:00 +02:00
|
|
|
err = alloc_pm_buffer(emu);
|
|
|
|
if (err < 0)
|
2021-07-15 09:58:55 +02:00
|
|
|
return err;
|
2005-11-17 16:14:10 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Initialize the effect engine */
|
2008-10-23 18:51:00 +02:00
|
|
|
err = snd_emu10k1_init_efx(emu);
|
|
|
|
if (err < 0)
|
2021-07-15 09:58:55 +02:00
|
|
|
return err;
|
2005-11-17 16:14:10 +01:00
|
|
|
snd_emu10k1_audio_enable(emu);
|
|
|
|
|
2015-05-29 07:56:42 +02:00
|
|
|
#ifdef CONFIG_SND_PROC_FS
|
2005-04-16 15:20:36 -07:00
|
|
|
snd_emu10k1_proc_init(emu);
|
2005-12-01 10:49:58 +01:00
|
|
|
#endif
|
2005-04-16 15:20:36 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-14 18:12:04 +02:00
|
|
|
#ifdef CONFIG_PM_SLEEP
|
2020-01-05 15:47:29 +01:00
|
|
|
static const unsigned char saved_regs[] = {
|
2005-11-17 16:14:10 +01:00
|
|
|
CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,
|
|
|
|
FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL,
|
|
|
|
ATKHLDM, DCYSUSM, LFOVAL2, IP, IFATN, PEFE, FMMOD, TREMFRQ, FM2FRQ2,
|
|
|
|
TEMPENV, ADCCR, FXWC, MICBA, ADCBA, FXBA,
|
|
|
|
MICBS, ADCBS, FXBS, CDCS, GPSCS, SPCS0, SPCS1, SPCS2,
|
|
|
|
SPBYPASS, AC97SLOT, CDSRCS, GPSRCS, ZVSRCS, MICIDX, ADCIDX, FXIDX,
|
|
|
|
0xff /* end */
|
|
|
|
};
|
2020-01-05 15:47:29 +01:00
|
|
|
static const unsigned char saved_regs_audigy[] = {
|
2023-04-22 18:10:19 +02:00
|
|
|
A_ADCIDX, A_MICIDX, A_FXWC1, A_FXWC2, A_EHC,
|
2005-11-17 16:14:10 +01:00
|
|
|
A_FXRT2, A_SENDAMOUNTS, A_FXRT1,
|
|
|
|
0xff /* end */
|
|
|
|
};
|
|
|
|
|
2012-12-06 12:35:10 -05:00
|
|
|
static int alloc_pm_buffer(struct snd_emu10k1 *emu)
|
2005-11-17 16:14:10 +01:00
|
|
|
{
|
|
|
|
int size;
|
|
|
|
|
|
|
|
size = ARRAY_SIZE(saved_regs);
|
|
|
|
if (emu->audigy)
|
|
|
|
size += ARRAY_SIZE(saved_regs_audigy);
|
treewide: Use array_size() in vmalloc()
The vmalloc() function has no 2-factor argument form, so multiplication
factors need to be wrapped in array_size(). This patch replaces cases of:
vmalloc(a * b)
with:
vmalloc(array_size(a, b))
as well as handling cases of:
vmalloc(a * b * c)
with:
vmalloc(array3_size(a, b, c))
This does, however, attempt to ignore constant size factors like:
vmalloc(4 * 1024)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
vmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
vmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
vmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
vmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
vmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
vmalloc(
- sizeof(TYPE) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT_ID
+ array_size(COUNT_ID, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT_ID)
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT_ID
+ array_size(COUNT_ID, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT_CONST)
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT_CONST
+ array_size(COUNT_CONST, sizeof(THING))
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
vmalloc(
- SIZE * COUNT
+ array_size(COUNT, SIZE)
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
vmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
vmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
vmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
vmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
vmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
vmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
vmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
vmalloc(C1 * C2 * C3, ...)
|
vmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants.
@@
expression E1, E2;
constant C1, C2;
@@
(
vmalloc(C1 * C2, ...)
|
vmalloc(
- E1 * E2
+ array_size(E1, E2)
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 14:27:11 -07:00
|
|
|
emu->saved_ptr = vmalloc(array3_size(4, NUM_G, size));
|
2008-10-23 18:51:00 +02:00
|
|
|
if (!emu->saved_ptr)
|
2005-11-17 16:14:10 +01:00
|
|
|
return -ENOMEM;
|
|
|
|
if (snd_emu10k1_efx_alloc_pm_buffer(emu) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
if (emu->card_capabilities->ca0151_chip &&
|
|
|
|
snd_p16v_alloc_pm_buffer(emu) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_pm_buffer(struct snd_emu10k1 *emu)
|
|
|
|
{
|
|
|
|
vfree(emu->saved_ptr);
|
|
|
|
snd_emu10k1_efx_free_pm_buffer(emu);
|
|
|
|
if (emu->card_capabilities->ca0151_chip)
|
|
|
|
snd_p16v_free_pm_buffer(emu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu)
|
|
|
|
{
|
|
|
|
int i;
|
2020-01-05 15:47:29 +01:00
|
|
|
const unsigned char *reg;
|
2005-11-17 16:14:10 +01:00
|
|
|
unsigned int *val;
|
|
|
|
|
|
|
|
val = emu->saved_ptr;
|
|
|
|
for (reg = saved_regs; *reg != 0xff; reg++)
|
|
|
|
for (i = 0; i < NUM_G; i++, val++)
|
|
|
|
*val = snd_emu10k1_ptr_read(emu, *reg, i);
|
|
|
|
if (emu->audigy) {
|
|
|
|
for (reg = saved_regs_audigy; *reg != 0xff; reg++)
|
|
|
|
for (i = 0; i < NUM_G; i++, val++)
|
|
|
|
*val = snd_emu10k1_ptr_read(emu, *reg, i);
|
|
|
|
}
|
|
|
|
if (emu->audigy)
|
2023-04-21 16:10:01 +02:00
|
|
|
emu->saved_a_iocfg = inw(emu->port + A_IOCFG);
|
2005-11-17 16:14:10 +01:00
|
|
|
emu->saved_hcfg = inl(emu->port + HCFG);
|
|
|
|
}
|
|
|
|
|
|
|
|
void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
|
|
|
|
{
|
2007-07-14 10:24:49 +01:00
|
|
|
if (emu->card_capabilities->ca_cardbus_chip)
|
|
|
|
snd_emu10k1_cardbus_init(emu);
|
2005-11-17 16:14:10 +01:00
|
|
|
if (emu->card_capabilities->ecard)
|
|
|
|
snd_emu10k1_ecard_init(emu);
|
2007-11-04 14:08:26 +00:00
|
|
|
else if (emu->card_capabilities->emu_model)
|
2008-10-23 18:51:00 +02:00
|
|
|
snd_emu10k1_emu1010_init(emu);
|
2005-11-17 16:14:10 +01:00
|
|
|
else
|
|
|
|
snd_emu10k1_ptr_write(emu, AC97SLOT, 0, AC97SLOT_CNTR|AC97SLOT_LFE);
|
2023-04-22 15:24:29 +02:00
|
|
|
snd_emu10k1_init(emu, emu->enable_ir);
|
2005-11-17 16:14:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu)
|
|
|
|
{
|
|
|
|
int i;
|
2020-01-05 15:47:29 +01:00
|
|
|
const unsigned char *reg;
|
2005-11-17 16:14:10 +01:00
|
|
|
unsigned int *val;
|
|
|
|
|
|
|
|
snd_emu10k1_audio_enable(emu);
|
|
|
|
|
|
|
|
/* resore for spdif */
|
|
|
|
if (emu->audigy)
|
2023-04-21 16:10:01 +02:00
|
|
|
outw(emu->saved_a_iocfg, emu->port + A_IOCFG);
|
2006-10-04 18:21:05 +02:00
|
|
|
outl(emu->saved_hcfg, emu->port + HCFG);
|
2005-11-17 16:14:10 +01:00
|
|
|
|
|
|
|
val = emu->saved_ptr;
|
|
|
|
for (reg = saved_regs; *reg != 0xff; reg++)
|
|
|
|
for (i = 0; i < NUM_G; i++, val++)
|
|
|
|
snd_emu10k1_ptr_write(emu, *reg, i, *val);
|
|
|
|
if (emu->audigy) {
|
|
|
|
for (reg = saved_regs_audigy; *reg != 0xff; reg++)
|
|
|
|
for (i = 0; i < NUM_G; i++, val++)
|
|
|
|
snd_emu10k1_ptr_write(emu, *reg, i, *val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|