/* * Default values for the effect slider controls, they are in order of their * effect NID's. Surround, Crystalizer, Dialog Plus, Smart Volume, and then * X-bass.
*/ staticconstunsignedint effect_slider_defaults[] = {67, 65, 50, 74, 50}; /* Amount of effect level sliders for ca0132_alt controls. */ #define EFFECT_LEVEL_SLIDERS 5
/* * DSP reqs for handling full-range speakers/bass redirection. If a speaker is * set as not being full range, and bass redirection is enabled, all * frequencies below the crossover frequency are redirected to the LFE * channel. If the surround configuration has no LFE channel, this can't be * enabled. X-Bass must be disabled when using these.
*/ enum speaker_range_reqs {
SPEAKER_BASS_REDIRECT = 0x15,
SPEAKER_BASS_REDIRECT_XOVER_FREQ = 0x16, /* Between 0x16-0x1a are the X-Bass reqs. */
SPEAKER_FULL_RANGE_FRONT_L_R = 0x1a,
SPEAKER_FULL_RANGE_CENTER_LFE = 0x1b,
SPEAKER_FULL_RANGE_REAR_L_R = 0x1c,
SPEAKER_FULL_RANGE_SURROUND_L_R = 0x1d,
SPEAKER_BASS_REDIRECT_SUB_GAIN = 0x1e,
};
/* * Definitions for the DSP req's to handle speaker tuning. These all belong to * module ID 0x96, the output effects module.
*/ enum speaker_tuning_reqs { /* * Currently, this value is always set to 0.0f. However, on Windows, * when selecting certain headphone profiles on the new Sound Blaster * connect software, the QUERY_SPEAKER_EQ_ADDRESS req on mid 0x80 is * sent. This gets the speaker EQ address area, which is then used to * send over (presumably) an equalizer profile for the specific * headphone setup. It is sent using the same method the DSP * firmware is uploaded with, which I believe is why the 'ctspeq.bin' * file exists in linux firmware tree but goes unused. It would also * explain why the QUERY_SPEAKER_EQ_ADDRESS req is defined but unused. * Once this profile is sent over, SPEAKER_TUNING_USE_SPEAKER_EQ is * set to 1.0f.
*/
SPEAKER_TUNING_USE_SPEAKER_EQ = 0x1f,
SPEAKER_TUNING_ENABLE_CENTER_EQ = 0x20,
SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL = 0x21,
SPEAKER_TUNING_FRONT_RIGHT_VOL_LEVEL = 0x22,
SPEAKER_TUNING_CENTER_VOL_LEVEL = 0x23,
SPEAKER_TUNING_LFE_VOL_LEVEL = 0x24,
SPEAKER_TUNING_REAR_LEFT_VOL_LEVEL = 0x25,
SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL = 0x26,
SPEAKER_TUNING_SURROUND_LEFT_VOL_LEVEL = 0x27,
SPEAKER_TUNING_SURROUND_RIGHT_VOL_LEVEL = 0x28, /* * Inversion is used when setting headphone virtualization to line * out. Not sure why this is, but it's the only place it's ever used.
*/
SPEAKER_TUNING_FRONT_LEFT_INVERT = 0x29,
SPEAKER_TUNING_FRONT_RIGHT_INVERT = 0x2a,
SPEAKER_TUNING_CENTER_INVERT = 0x2b,
SPEAKER_TUNING_LFE_INVERT = 0x2c,
SPEAKER_TUNING_REAR_LEFT_INVERT = 0x2d,
SPEAKER_TUNING_REAR_RIGHT_INVERT = 0x2e,
SPEAKER_TUNING_SURROUND_LEFT_INVERT = 0x2f,
SPEAKER_TUNING_SURROUND_RIGHT_INVERT = 0x30, /* Delay is used when setting surround speaker distance in Windows. */
SPEAKER_TUNING_FRONT_LEFT_DELAY = 0x31,
SPEAKER_TUNING_FRONT_RIGHT_DELAY = 0x32,
SPEAKER_TUNING_CENTER_DELAY = 0x33,
SPEAKER_TUNING_LFE_DELAY = 0x34,
SPEAKER_TUNING_REAR_LEFT_DELAY = 0x35,
SPEAKER_TUNING_REAR_RIGHT_DELAY = 0x36,
SPEAKER_TUNING_SURROUND_LEFT_DELAY = 0x37,
SPEAKER_TUNING_SURROUND_RIGHT_DELAY = 0x38, /* Of these two, only mute seems to ever be used. */
SPEAKER_TUNING_MAIN_VOLUME = 0x39,
SPEAKER_TUNING_MUTE = 0x3a,
};
/* * DSP volume setting structs. Req 1 is left volume, req 2 is right volume, * and I don't know what the third req is, but it's always zero. I assume it's * some sort of update or set command to tell the DSP there's new volume info.
*/ #define DSP_VOL_OUT 0 #define DSP_VOL_IN 1
struct ct_dsp_volume_ctl {
hda_nid_t vnid; int mid; /* module ID*/ unsignedint reqs[3]; /* scp req ID */
};
/* * Data structures for storing audio router remapping data. These are used to * remap a currently active streams ports.
*/ struct chipio_stream_remap_data { unsignedint stream_id; unsignedint count;
/* * Control flag IDs
*/ enum control_flag_id { /* Connection manager stream setup is bypassed/enabled */
CONTROL_FLAG_C_MGR = 0, /* DSP DMA is bypassed/enabled */
CONTROL_FLAG_DMA = 1, /* 8051 'idle' mode is disabled/enabled */
CONTROL_FLAG_IDLE_ENABLE = 2, /* Tracker for the SPDIF-in path is bypassed/enabled */
CONTROL_FLAG_TRACKER = 3, /* DigitalOut to Spdif2Out connection is disabled/enabled */
CONTROL_FLAG_SPDIF2OUT = 4, /* Digital Microphone is disabled/enabled */
CONTROL_FLAG_DMIC = 5, /* ADC_B rate is 48 kHz/96 kHz */
CONTROL_FLAG_ADC_B_96KHZ = 6, /* ADC_C rate is 48 kHz/96 kHz */
CONTROL_FLAG_ADC_C_96KHZ = 7, /* DAC rate is 48 kHz/96 kHz (affects all DACs) */
CONTROL_FLAG_DAC_96KHZ = 8, /* DSP rate is 48 kHz/96 kHz */
CONTROL_FLAG_DSP_96KHZ = 9, /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */
CONTROL_FLAG_SRC_CLOCK_196MHZ = 10, /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */
CONTROL_FLAG_SRC_RATE_96KHZ = 11, /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */
CONTROL_FLAG_DECODE_LOOP = 12, /* De-emphasis filter on DAC-1 disabled/enabled */
CONTROL_FLAG_DAC1_DEEMPHASIS = 13, /* De-emphasis filter on DAC-2 disabled/enabled */
CONTROL_FLAG_DAC2_DEEMPHASIS = 14, /* De-emphasis filter on DAC-3 disabled/enabled */
CONTROL_FLAG_DAC3_DEEMPHASIS = 15, /* High-pass filter on ADC_B disabled/enabled */
CONTROL_FLAG_ADC_B_HIGH_PASS = 16, /* High-pass filter on ADC_C disabled/enabled */
CONTROL_FLAG_ADC_C_HIGH_PASS = 17, /* Common mode on Port_A disabled/enabled */
CONTROL_FLAG_PORT_A_COMMON_MODE = 18, /* Common mode on Port_D disabled/enabled */
CONTROL_FLAG_PORT_D_COMMON_MODE = 19, /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */
CONTROL_FLAG_PORT_A_10KOHM_LOAD = 20, /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */
CONTROL_FLAG_PORT_D_10KOHM_LOAD = 21, /* ASI rate is 48kHz/96kHz */
CONTROL_FLAG_ASI_96KHZ = 22, /* DAC power settings able to control attached ports no/yes */
CONTROL_FLAG_DACS_CONTROL_PORTS = 23, /* Clock Stop OK reporting is disabled/enabled */
CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24, /* Number of control flags */
CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1)
};
/* * Control parameter IDs
*/ enum control_param_id { /* 0: None, 1: Mic1In*/
CONTROL_PARAM_VIP_SOURCE = 1, /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */
CONTROL_PARAM_SPDIF1_SOURCE = 2, /* Port A output stage gain setting to use when 16 Ohm output
* impedance is selected*/
CONTROL_PARAM_PORTA_160OHM_GAIN = 8, /* Port D output stage gain setting to use when 16 Ohm output
* impedance is selected*/
CONTROL_PARAM_PORTD_160OHM_GAIN = 10,
/* * This control param name was found in the 8051 memory, and makes * sense given the fact the AE-5 uses it and has the ASI flag set.
*/
CONTROL_PARAM_ASI = 23,
/* Stream Control */
/* Select stream with the given ID */
CONTROL_PARAM_STREAM_ID = 24, /* Source connection point for the selected stream */
CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25, /* Destination connection point for the selected stream */
CONTROL_PARAM_STREAM_DEST_CONN_POINT = 26, /* Number of audio channels in the selected stream */
CONTROL_PARAM_STREAMS_CHANNELS = 27, /*Enable control for the selected stream */
CONTROL_PARAM_STREAM_CONTROL = 28,
/* Connection Point Control */
/* Select connection point with the given ID */
CONTROL_PARAM_CONN_POINT_ID = 29, /* Connection point sample rate */
CONTROL_PARAM_CONN_POINT_SAMPLE_RATE = 30,
/* Node Control */
/* Select HDA node with the given ID */
CONTROL_PARAM_NODE_ID = 31
};
/* * Dsp Io Status codes
*/ enum hda_vendor_status_dspio { /* Success */
VENDOR_STATUS_DSPIO_OK = 0x00, /* Busy, unable to accept new command, the host must retry */
VENDOR_STATUS_DSPIO_BUSY = 0x01, /* SCP command queue is full */
VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL = 0x02, /* SCP response queue is empty */
VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03
};
/* * Chip Io Status codes
*/ enum hda_vendor_status_chipio { /* Success */
VENDOR_STATUS_CHIPIO_OK = 0x00, /* Busy, unable to accept new command, the host must retry */
VENDOR_STATUS_CHIPIO_BUSY = 0x01
};
/* mixer and effects related */ unsignedchar dmic_ctl; int cur_out_type; int cur_mic_type; long vnode_lvol[VNODES_COUNT]; long vnode_rvol[VNODES_COUNT]; long vnode_lswitch[VNODES_COUNT]; long vnode_rswitch[VNODES_COUNT]; long effects_switch[EFFECTS_COUNT]; long voicefx_val; long cur_mic_boost; /* ca0132_alt control related values */ unsignedchar in_enum_val; unsignedchar out_enum_val; unsignedchar channel_cfg_val; unsignedchar speaker_range_val[2]; unsignedchar mic_boost_enum_val; unsignedchar smart_volume_setting; unsignedchar bass_redirection_val; long bass_redirect_xover_freq; long fx_ctl_val[EFFECT_LEVEL_SLIDERS]; long xbass_xover_freq; long eq_preset_val; unsignedint tlv[4]; struct hda_vmaster_mute_hook vmaster_mute; /* AE-5 Control values */ unsignedchar ae5_headphone_gain_val; unsignedchar ae5_filter_val; /* ZxR Control Values */ unsignedchar zxr_gain_set;
#ifdef ENABLE_TUNING_CONTROLS long cur_ctl_vals[TUNING_CTLS_COUNT]; #endif /* * The Recon3D, Sound Blaster Z, Sound Blaster ZxR, and Sound Blaster * AE-5 all use PCI region 2 to toggle GPIO and other currently unknown * things.
*/ bool use_pci_mmio; void __iomem *mem_base;
/* * Whether or not to use the alt functions like alt_select_out, * alt_select_in, etc. Only used on desktop codecs for now, because of * surround sound support.
*/ bool use_alt_functions;
/* * Whether or not to use alt controls: volume effect sliders, EQ * presets, smart volume presets, and new control names with FX prefix. * Renames PlayEnhancement and CrystalVoice too.
*/ bool use_alt_controls;
};
/* Sound Blaster Z pin configs taken from Windows Driver */ staticconststruct hda_pintbl sbz_pincfgs[] = {
{ 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x01c510f0 }, /* SPDIF In */
{ 0x0f, 0x0221701f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x01017014 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Sound Blaster ZxR pin configs taken from Windows Driver */ staticconststruct hda_pintbl zxr_pincfgs[] = {
{ 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
{ 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01017111 }, /* Port D -- Center/LFE */
{ 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Recon3D pin configs taken from Windows Driver */ staticconststruct hda_pintbl r3d_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x01c520f0 }, /* SPDIF In */
{ 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Sound Blaster AE-5 pin configs taken from Windows Driver */ staticconststruct hda_pintbl ae5_pincfgs[] = {
{ 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x01c510f0 }, /* SPDIF In */
{ 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
{ 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x012170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
{ 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x50d000f0 }, /* N/A */
{}
};
/* Recon3D integrated pin configs taken from Windows Driver */ staticconststruct hda_pintbl r3di_pincfgs[] = {
{ 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
{ 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
{ 0x0d, 0x014510f0 }, /* Digital Out */
{ 0x0e, 0x41c520f0 }, /* SPDIF In */
{ 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
{ 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
{ 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
{ 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
{ 0x13, 0x908700f0 }, /* What U Hear In*/
{ 0x18, 0x500000f0 }, /* N/A */
{}
};
/* send bits of data specified by reg */ do {
res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
reg, data); if (res == VENDOR_STATUS_CHIPIO_OK) return 0;
msleep(20);
} while (time_before(jiffies, timeout));
return -EIO;
}
/* * Write chip address through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_write_address(struct hda_codec *codec, unsignedint chip_addx)
{ struct ca0132_spec *spec = codec->spec; int res;
if (spec->curr_chip_addx == chip_addx) return 0;
/* send low 16 bits of the address */
res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW,
chip_addx & 0xffff);
if (res != -EIO) { /* send high 16 bits of the address */
res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH,
chip_addx >> 16);
}
/* * Write data through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_write_data(struct hda_codec *codec, unsignedint data)
{ struct ca0132_spec *spec = codec->spec; int res;
/* send low 16 bits of the data */
res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff);
if (res != -EIO) { /* send high 16 bits of the data */
res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH,
data >> 16);
}
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
(spec->curr_chip_addx + 4) : ~0U; return res;
}
/* * Write multiple data through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_write_data_multiple(struct hda_codec *codec, const u32 *data, unsignedint count)
{ int status = 0;
while ((count-- != 0) && (status == 0))
status = chipio_write_data(codec, *data++);
return status;
}
/* * Read data through the vendor widget -- NOT protected by the Mutex!
*/ staticint chipio_read_data(struct hda_codec *codec, unsignedint *data)
{ struct ca0132_spec *spec = codec->spec; int res;
/* post read */
res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0);
if (res != -EIO) { /* read status */
res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
}
if (res != -EIO) { /* read data */
*data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_HIC_READ_DATA,
0);
}
/*If no error encountered, automatically increment the address
as per chip behaviour*/
spec->curr_chip_addx = (res != -EIO) ?
(spec->curr_chip_addx + 4) : ~0U; return res;
}
/* * Write given value to the given address through the chip I/O widget. * protected by the Mutex
*/ staticint chipio_write(struct hda_codec *codec, unsignedint chip_addx, constunsignedint data)
{ struct ca0132_spec *spec = codec->spec; int err;
mutex_lock(&spec->chipio_mutex);
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx); if (err < 0) gotoexit;
err = chipio_write_data(codec, data); if (err < 0) gotoexit;
/* * Write given value to the given address through the chip I/O widget. * not protected by the Mutex
*/ staticint chipio_write_no_mutex(struct hda_codec *codec, unsignedint chip_addx, constunsignedint data)
{ int err;
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx); if (err < 0) gotoexit;
err = chipio_write_data(codec, data); if (err < 0) gotoexit;
exit: return err;
}
/* * Write multiple values to the given address through the chip I/O widget. * protected by the Mutex
*/ staticint chipio_write_multiple(struct hda_codec *codec,
u32 chip_addx, const u32 *data, unsignedint count)
{ struct ca0132_spec *spec = codec->spec; int status;
mutex_lock(&spec->chipio_mutex);
status = chipio_write_address(codec, chip_addx); if (status < 0) goto error;
status = chipio_write_data_multiple(codec, data, count);
error:
mutex_unlock(&spec->chipio_mutex);
return status;
}
/* * Read the given address through the chip I/O widget * protected by the Mutex
*/ staticint chipio_read(struct hda_codec *codec, unsignedint chip_addx, unsignedint *data)
{ struct ca0132_spec *spec = codec->spec; int err;
mutex_lock(&spec->chipio_mutex);
/* write the address, and if successful proceed to write data */
err = chipio_write_address(codec, chip_addx); if (err < 0) gotoexit;
err = chipio_read_data(codec, data); if (err < 0) gotoexit;
/* * Set chip parameters through the chip I/O widget. NO MUTEX.
*/ staticvoid chipio_set_control_param_no_mutex(struct hda_codec *codec, enum control_param_id param_id, int param_val)
{ int val;
if ((param_id < 32) && (param_val < 8)) {
val = (param_val << 5) | (param_id);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_SET, val);
} else { if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_ID_SET,
param_id);
snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
param_val);
}
}
} /* * Connect stream to a source point, and then connect * that source point to a destination point.
*/ staticvoid chipio_set_stream_source_dest(struct hda_codec *codec, int streamid, int source_point, int dest_point)
{
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_ID, streamid);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_SOURCE_CONN_POINT, source_point);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_DEST_CONN_POINT, dest_point);
}
/* * Set number of channels in the selected stream.
*/ staticvoid chipio_set_stream_channels(struct hda_codec *codec, int streamid, unsignedint channels)
{
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAM_ID, streamid);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_STREAMS_CHANNELS, channels);
}
/* * Set sampling rate of the connection point. NO MUTEX.
*/ staticvoid chipio_set_conn_rate_no_mutex(struct hda_codec *codec, int connid, enum ca0132_sample_rate rate)
{
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_CONN_POINT_ID, connid);
chipio_set_control_param_no_mutex(codec,
CONTROL_PARAM_CONN_POINT_SAMPLE_RATE, rate);
}
/* * Set sampling rate of the connection point.
*/ staticvoid chipio_set_conn_rate(struct hda_codec *codec, int connid, enum ca0132_sample_rate rate)
{
chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_ID, connid);
chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_SAMPLE_RATE,
rate);
}
/* * Writes to the 8051's internal address space directly instead of indirectly, * giving access to the special function registers located at addresses * 0x80-0xFF.
*/ staticvoid chipio_8051_write_direct(struct hda_codec *codec, unsignedint addr, unsignedint data)
{ unsignedint verb;
/* * Writes to the 8051's exram, which has 16-bits of address space. * Data at addresses 0x2000-0x7fff is mirrored to 0x8000-0xdfff. * Data at 0x8000-0xdfff can also be used as program memory for the 8051 by * setting the pmem bank selection SFR. * 0xe000-0xffff is always mapped as program memory, with only 0xf000-0xffff * being writable.
*/ staticvoid chipio_8051_set_address(struct hda_codec *codec, unsignedint addr)
{ unsignedint tmp;
/* send bits of data specified by reg to dsp */ do {
res = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, reg, data); if ((res >= 0) && (res != VENDOR_STATUS_DSPIO_BUSY)) return res;
msleep(20);
} while (time_before(jiffies, timeout));
return -EIO;
}
/* * Wait for DSP to be ready for commands
*/ staticvoid dspio_write_wait(struct hda_codec *codec)
{ int status; unsignedlong timeout = jiffies + msecs_to_jiffies(1000);
do {
status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_STATUS, 0); if ((status == VENDOR_STATUS_DSPIO_OK) ||
(status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY)) break;
msleep(1);
} while (time_before(jiffies, timeout));
}
/* * Write SCP data to DSP
*/ staticint dspio_write(struct hda_codec *codec, unsignedint scp_data)
{ struct ca0132_spec *spec = codec->spec; int status;
dspio_write_wait(codec);
mutex_lock(&spec->chipio_mutex);
status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW,
scp_data & 0xffff); if (status < 0) goto error;
status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH,
scp_data >> 16); if (status < 0) goto error;
/* OK, now check if the write itself has executed*/
status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
VENDOR_DSPIO_STATUS, 0);
error:
mutex_unlock(&spec->chipio_mutex);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.