/* Some vector commands involve the DSP reading or writing data to and from the commpage;ifyousendoneofthesecommandstotheDSP,itwillcompletethe commandandthenwriteanon-zerovaluetotheHandshakefieldinthe
comm page. This function waits for the handshake to show up. */ staticint wait_handshake(struct echoaudio *chip)
{ int i;
/* Wait up to 20ms for the handshake from the DSP */ for (i = 0; i < HANDSHAKE_TIMEOUT; i++) { /* Look for the handshake value */
barrier(); if (chip->comm_page->handshake) { return0;
}
udelay(1);
}
dev_err(chip->card->dev, "wait_handshake(): Timeout waiting for DSP\n"); return -EBUSY;
}
/* Much of the interaction between the DSP and the driver is done via vector commands;send_vectorwritesavectorcommandtotheDSP.Typically,this causestheDSPtoreadorwritefieldsinthecommpage.
PCI posting is not required thanks to the handshake logic. */ staticint send_vector(struct echoaudio *chip, u32 command)
{ int i;
wmb(); /* Flush all pending writes before sending the command */
/* Wait up to 100ms for the "vector busy" bit to be off */ for (i = 0; i < VECTOR_BUSY_TIMEOUT; i++) { if (!(get_dsp_register(chip, CHI32_VECTOR_REG) &
CHI32_VECTOR_BUSY)) {
set_dsp_register(chip, CHI32_VECTOR_REG, command); /*if (i) DE_ACT(("send_vector time: %d\n", i));*/ return0;
}
udelay(1);
}
dev_err(chip->card->dev, "timeout on send_vector\n"); return -EBUSY;
}
/* write_dsp writes a 32-bit value to the DSP; this is used almost
exclusively for loading the DSP. */ staticint write_dsp(struct echoaudio *chip, u32 data)
{
u32 status, i;
for (i = 0; i < 10000000; i++) { /* timeout = 10s */
status = get_dsp_register(chip, CHI32_STATUS_REG); if ((status & CHI32_STATUS_HOST_WRITE_EMPTY) != 0) {
set_dsp_register(chip, CHI32_DATA_REG, data);
wmb(); /* write it immediately */ return0;
}
udelay(1);
cond_resched();
}
chip->bad_board = true; /* Set true until DSP re-loaded */
dev_dbg(chip->card->dev, "write_dsp: Set bad_board to true\n"); return -EIO;
}
/* read_dsp reads a 32-bit value from the DSP; this is used almost
exclusively for loading the DSP and checking the status of the ASIC. */ staticint read_dsp(struct echoaudio *chip, u32 *data)
{
u32 status, i;
for (i = 0; i < READ_DSP_TIMEOUT; i++) {
status = get_dsp_register(chip, CHI32_STATUS_REG); if ((status & CHI32_STATUS_HOST_READ_FULL) != 0) {
*data = get_dsp_register(chip, CHI32_DATA_REG); return0;
}
udelay(1);
cond_resched();
}
chip->bad_board = true; /* Set true until DSP re-loaded */
dev_err(chip->card->dev, "read_dsp: Set bad_board to true\n"); return -EIO;
}
/* This function is used to read back the serial number from the DSP; thisistriggeredbytheSET_COMMPAGE_ADDRcommand. OnlysomeearlyEchogalsproductshaveserialnumbersintheROM; theserialnumberisnotused,butyoustillneedtodothisas
part of the DSP load process. */ staticint read_sn(struct echoaudio *chip)
{ int i;
u32 sn[6];
for (i = 0; i < 5; i++) { if (read_dsp(chip, &sn[i])) {
dev_err(chip->card->dev, "Failed to read serial number\n"); return -EIO;
}
}
dev_dbg(chip->card->dev, "Read serial number %08x %08x %08x %08x %08x\n",
sn[0], sn[1], sn[2], sn[3], sn[4]); return0;
}
#ifndef ECHOCARD_HAS_ASIC /* This card has no ASIC, just return ok */ staticinlineint check_asic_status(struct echoaudio *chip)
{
chip->asic_loaded = true; return0;
}
#endif/* !ECHOCARD_HAS_ASIC */
#ifdef ECHOCARD_HAS_ASIC
/* Load ASIC code - done after the DSP is loaded */ staticint load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
{ conststruct firmware *fw; int err;
u32 i, size;
u8 *code;
err = get_firmware(&fw, chip, asic); if (err < 0) {
dev_warn(chip->card->dev, "Firmware not found !\n"); return err;
}
code = (u8 *)fw->data;
size = fw->size;
/* Send the "Here comes the ASIC" command */ if (write_dsp(chip, cmd) < 0) goto la_error;
/* Write length of ASIC file in bytes */ if (write_dsp(chip, size) < 0) goto la_error;
for (i = 0; i < size; i++) { if (write_dsp(chip, code[i]) < 0) goto la_error;
}
free_firmware(fw, chip); return0;
la_error:
dev_err(chip->card->dev, "failed on write_dsp\n");
free_firmware(fw, chip); return -EIO;
}
#endif/* ECHOCARD_HAS_ASIC */
#ifdef DSP_56361
/* Install the resident loader for 56361 DSPs; The resident loader is on theEPROMontheboardfor56301DSP.Theresidentloaderisatinylittle
program that is used to load the real DSP code. */ staticint install_resident_loader(struct echoaudio *chip)
{
u32 address; int index, words, i;
u16 *code;
u32 status; conststruct firmware *fw;
/* 56361 cards only! This check is required by the old 56301-based
Mona and Gina24 */ if (chip->device_id != DEVICE_ID_56361) return0;
/* Look to see if the resident loader is present. If the resident
loader is already installed, host flag 5 will be on. */
status = get_dsp_register(chip, CHI32_STATUS_REG); if (status & CHI32_STATUS_REG_HF5) {
dev_dbg(chip->card->dev, "Resident loader already installed; status is 0x%x\n",
status); return0;
}
i = get_firmware(&fw, chip, FW_361_LOADER); if (i < 0) {
dev_warn(chip->card->dev, "Firmware not found !\n"); return i;
}
/* The DSP code is an array of 16 bit words. The array is divided up intosections.Thefirstwordofeachsectionisthesizeinwords, followedbythesectiontype. SinceDSPaddressesanddataare24bitswide,theyeachtakeuptwo 16bitwordsinthearray. Thisisalotliketheotherloaderloop,butit'snotaloop,you
don't write the memory type, and you don't write a zero at the end. */
/* Set DSP format bits for 24 bit mode */
set_dsp_register(chip, CHI32_CONTROL_REG,
get_dsp_register(chip, CHI32_CONTROL_REG) | 0x900);
code = (u16 *)fw->data;
/* Skip the header section; the first word in the array is the size ofthefirstsection,sothefirstrealsectionofcodeispointed
to by Code[0]. */
index = code[0];
/* Skip the section size, LRS block type, and DSP memory type */
index += 3;
/* Get the number of DSP words to write */
words = code[index++];
/* Get the DSP address for this block; 24 bits, so build from two words */
address = ((u32)code[index] << 16) + code[index + 1];
index += 2;
/* Write the count to the DSP */ if (write_dsp(chip, words)) {
dev_err(chip->card->dev, "install_resident_loader: Failed to write word count!\n"); goto irl_error;
} /* Write the DSP address */ if (write_dsp(chip, address)) {
dev_err(chip->card->dev, "install_resident_loader: Failed to write DSP address!\n"); goto irl_error;
} /* Write out this block of code to the DSP */ for (i = 0; i < words; i++) {
u32 data;
data = ((u32)code[index] << 16) + code[index + 1]; if (write_dsp(chip, data)) {
dev_err(chip->card->dev, "install_resident_loader: Failed to write DSP code\n"); goto irl_error;
}
index += 2;
}
/* Wait for flag 5 to come up */ for (i = 0; i < 200; i++) { /* Timeout is 50us * 200 = 10ms */
udelay(50);
status = get_dsp_register(chip, CHI32_STATUS_REG); if (status & CHI32_STATUS_REG_HF5) break;
}
if (i == 200) {
dev_err(chip->card->dev, "Resident loader failed to set HF5\n"); goto irl_error;
}
if (chip->dsp_code == code) {
dev_warn(chip->card->dev, "DSP is already loaded!\n"); return0;
}
chip->bad_board = true; /* Set true until DSP loaded */
chip->dsp_code = NULL; /* Current DSP code not loaded */
chip->asic_loaded = false; /* Loading the DSP code will reset the ASIC */
dev_dbg(chip->card->dev, "load_dsp: Set bad_board to true\n");
/* If this board requires a resident loader, install it. */ #ifdef DSP_56361
i = install_resident_loader(chip); if (i < 0) return i; #endif
/* Wait 10ms for HF3 to indicate that software reset is complete */ for (i = 0; i < 1000; i++) { /* Timeout is 10us * 1000 = 10ms */ if (get_dsp_register(chip, CHI32_STATUS_REG) &
CHI32_STATUS_REG_HF3) break;
udelay(10);
}
if (i == 1000) {
dev_err(chip->card->dev, "load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n"); return -EIO;
}
/* Set DSP format bits for 24 bit mode now that soft reset is done */
set_dsp_register(chip, CHI32_CONTROL_REG,
get_dsp_register(chip, CHI32_CONTROL_REG) | 0x900);
/* Main loader loop */
index = code[0]; for (;;) { int block_type, mem_type;
/* Total Block Size */
index++;
/* Block Type */
block_type = code[index]; if (block_type == 4) /* We're finished */ break;
index++;
/* Memory Type P=0,X=1,Y=2 */
mem_type = code[index++];
/* Block Code Size */
words = code[index++]; if (words == 0) /* We're finished */ break;
if (write_dsp(chip, words) < 0) {
dev_err(chip->card->dev, "load_dsp: failed to write number of DSP words\n"); return -EIO;
} if (write_dsp(chip, address) < 0) {
dev_err(chip->card->dev, "load_dsp: failed to write DSP address\n"); return -EIO;
} if (write_dsp(chip, mem_type) < 0) {
dev_err(chip->card->dev, "load_dsp: failed to write DSP memory type\n"); return -EIO;
} /* Code */ for (i = 0; i < words; i++, index+=2) {
data = ((u32)code[index] << 16) + code[index + 1]; if (write_dsp(chip, data) < 0) {
dev_err(chip->card->dev, "load_dsp: failed to write DSP data\n"); return -EIO;
}
}
}
if (write_dsp(chip, 0) < 0) { /* We're done!!! */
dev_err(chip->card->dev, "load_dsp: Failed to write final zero\n"); return -EIO;
}
udelay(10);
for (i = 0; i < 5000; i++) { /* Timeout is 100us * 5000 = 500ms */ /* Wait for flag 4 - indicates that the DSP loaded OK */ if (get_dsp_register(chip, CHI32_STATUS_REG) &
CHI32_STATUS_REG_HF4) {
set_dsp_register(chip, CHI32_CONTROL_REG,
get_dsp_register(chip, CHI32_CONTROL_REG) & ~0x1b00);
if (write_dsp(chip, DSP_FNC_SET_COMMPAGE_ADDR) < 0) {
dev_err(chip->card->dev, "load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"); return -EIO;
}
if (write_dsp(chip, chip->comm_page_phys) < 0) {
dev_err(chip->card->dev, "load_dsp: Failed to write comm page address\n"); return -EIO;
}
/* Get the serial number via slave mode. ThisistriggeredbytheSET_COMMPAGE_ADDRcommand. Wedon'tactuallyusetheserialnumberbutwehaveto
get it as part of the DSP init voodoo. */ if (read_sn(chip) < 0) {
dev_err(chip->card->dev, "load_dsp: Failed to read serial number\n"); return -EIO;
}
chip->dsp_code = code; /* Show which DSP code loaded */
chip->bad_board = false; /* DSP OK */ return0;
}
udelay(100);
}
dev_err(chip->card->dev, "load_dsp: DSP load timed out waiting for HF4\n"); return -EIO;
}
/* load_firmware takes care of loading the DSP and any ASIC code. */ staticint load_firmware(struct echoaudio *chip)
{ conststruct firmware *fw; int box_type, err;
if (snd_BUG_ON(!chip->comm_page)) return -EPERM;
/* See if the ASIC is present and working - only if the DSP is already loaded */ if (chip->dsp_code) {
box_type = check_asic_status(chip); if (box_type >= 0) return box_type; /* ASIC check failed; force the DSP to reload */
chip->dsp_code = NULL;
}
/* Set the nominal level for an input or output bus (true = -10dBV, false = +4dBu) */ staticint set_nominal_level(struct echoaudio *chip, u16 index, char consumer)
{ if (snd_BUG_ON(index >= num_busses_out(chip) + num_busses_in(chip))) return -EINVAL;
/* Wait for the handshake (OK even if ASIC is not loaded) */ if (wait_handshake(chip)) return -EIO;
/* Set the gain for a single physical output channel (dB). */ staticint set_output_gain(struct echoaudio *chip, u16 channel, s8 gain)
{ if (snd_BUG_ON(channel >= num_busses_out(chip))) return -EINVAL;
if (wait_handshake(chip)) return -EIO;
/* Save the new value */
chip->output_gain[channel] = gain;
chip->comm_page->line_out_level[channel] = gain; return0;
}
#ifdef ECHOCARD_HAS_MONITOR /* Set the monitor level from an input bus to an output bus. */ staticint set_monitor_gain(struct echoaudio *chip, u16 output, u16 input,
s8 gain)
{ if (snd_BUG_ON(output >= num_busses_out(chip) ||
input >= num_busses_in(chip))) return -EINVAL;
/* Tell the DSP to read and update output, nominal & monitor levels in comm page. */ staticint update_output_line_level(struct echoaudio *chip)
{ if (wait_handshake(chip)) return -EIO;
clear_handshake(chip); return send_vector(chip, DSP_VC_UPDATE_OUTVOL);
}
/* Tell the DSP to read and update input levels in comm page */ staticint update_input_line_level(struct echoaudio *chip)
{ if (wait_handshake(chip)) return -EIO;
clear_handshake(chip); return send_vector(chip, DSP_VC_UPDATE_INGAIN);
}
/* set_meters_on turns the meters on or off. If meters are turned on, the DSP
will write the meter and clock detect values to the comm page at about 30Hz */ staticvoid set_meters_on(struct echoaudio *chip, char on)
{ if (on && !chip->meters_enabled) {
send_vector(chip, DSP_VC_METERS_ON);
chip->meters_enabled = 1;
} elseif (!on && chip->meters_enabled) {
send_vector(chip, DSP_VC_METERS_OFF);
chip->meters_enabled = 0;
memset((s8 *)chip->comm_page->vu_meter, ECHOGAIN_MUTED,
DSP_MAXPIPES);
memset((s8 *)chip->comm_page->peak_meter, ECHOGAIN_MUTED,
DSP_MAXPIPES);
}
}
/* Fill out an the given array using the current values in the comm page. MetersarewritteninthecommpagebytheDSPinthisorder: Outputbusses Inputbusses Outputpipes(vmixercardsonly)
Thisfunctionassumestherearenomorethan16in/outbussesorpipes
Meters is an array [3][16][2] of long. */ staticvoid get_audio_meters(struct echoaudio *chip, long *meters)
{ unsignedint i, m, n;
for (i = 0 ; i < 96; i++)
meters[i] = 0;
for (m = 0, n = 0, i = 0; i < num_busses_out(chip); i++, m++) {
meters[n++] = chip->comm_page->vu_meter[m];
meters[n++] = chip->comm_page->peak_meter[m];
}
for (n = 32, i = 0; i < num_busses_in(chip); i++, m++) {
meters[n++] = chip->comm_page->vu_meter[m];
meters[n++] = chip->comm_page->peak_meter[m];
} #ifdef ECHOCARD_HAS_VMIXER for (n = 64, i = 0; i < num_pipes_out(chip); i++, m++) {
meters[n++] = chip->comm_page->vu_meter[m];
meters[n++] = chip->comm_page->peak_meter[m];
} #endif
}
staticint restore_dsp_rettings(struct echoaudio *chip)
{ int i, o, err;
err = check_asic_status(chip); if (err < 0) return err;
/* Gina20/Darla20 only. Should be harmless for other cards. */
chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF;
chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF;
chip->comm_page->handshake = cpu_to_le32(0xffffffff);
/* Restore output busses */ for (i = 0; i < num_busses_out(chip); i++) {
err = set_output_gain(chip, i, chip->output_gain[i]); if (err < 0) return err;
}
#ifdef ECHOCARD_HAS_VMIXER for (i = 0; i < num_pipes_out(chip); i++) for (o = 0; o < num_busses_out(chip); o++) {
err = set_vmixer_gain(chip, o, i,
chip->vmixer_gain[o][i]); if (err < 0) return err;
} if (update_vmixer_level(chip) < 0) return -EIO; #endif/* ECHOCARD_HAS_VMIXER */
#ifdef ECHOCARD_HAS_MONITOR for (o = 0; o < num_busses_out(chip); o++) for (i = 0; i < num_busses_in(chip); i++) {
err = set_monitor_gain(chip, o, i,
chip->monitor_gain[o][i]); if (err < 0) return err;
} #endif/* ECHOCARD_HAS_MONITOR */
#ifdef ECHOCARD_HAS_INPUT_GAIN for (i = 0; i < num_busses_in(chip); i++) {
err = set_input_gain(chip, i, chip->input_gain[i]); if (err < 0) return err;
} #endif/* ECHOCARD_HAS_INPUT_GAIN */
err = update_output_line_level(chip); if (err < 0) return err;
err = update_input_line_level(chip); if (err < 0) return err;
err = set_sample_rate(chip, chip->sample_rate); if (err < 0) return err;
if (chip->meters_enabled) {
err = send_vector(chip, DSP_VC_METERS_ON); if (err < 0) return err;
}
#ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH if (set_digital_mode(chip, chip->digital_mode) < 0) return -EIO; #endif
#ifdef ECHOCARD_HAS_DIGITAL_IO if (set_professional_spdif(chip, chip->professional_spdif) < 0) return -EIO; #endif
#ifdef ECHOCARD_HAS_PHANTOM_POWER if (set_phantom_power(chip, chip->phantom_power) < 0) return -EIO; #endif
#ifdef ECHOCARD_HAS_EXTERNAL_CLOCK /* set_input_clock() also restores automute setting */ if (set_input_clock(chip, chip->input_clock) < 0) return -EIO; #endif
#ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH if (set_output_clock(chip, chip->output_clock) < 0) return -EIO; #endif
if (wait_handshake(chip) < 0) return -EIO;
clear_handshake(chip); if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) return -EIO;
/* set_audio_format() sets the format of the audio data in host memory for thispipe.Notethat_MS_(mono-to-stereo)playbackmodesarenotusedbyALSA
but they are here because they are just mono while capturing */ staticvoid set_audio_format(struct echoaudio *chip, u16 pipe_index, conststruct audioformat *format)
{
u16 dsp_format;
/* start_transport starts transport for a set of pipes. Thebits1inchannel_maskspecifywhatpipestostart.Onlythebitofthe firstchannelmustbeset,regardlessitsinterleave.
Same thing for pause_ and stop_ -trasport below. */ staticint start_transport(struct echoaudio *chip, u32 channel_mask,
u32 cyclic_mask)
{
/* Go to sleep */ if (chip->dsp_code) { /* Make load_firmware do a complete reload */
chip->dsp_code = NULL; /* Put the DSP to sleep */ return send_vector(chip, DSP_VC_GO_COMATOSE);
} return0;
}
/* Fills the comm page with default values */ staticint init_dsp_comm_page(struct echoaudio *chip)
{ /* Check if the compiler added extra padding inside the structure */ if (offsetof(struct comm_page, midi_output) != 0xbe0) {
dev_err(chip->card->dev, "init_dsp_comm_page() - Invalid struct comm_page structure\n"); return -EPERM;
}
/* Init all the basic stuff */
chip->card_name = ECHOCARD_NAME;
chip->bad_board = true; /* Set true until DSP loaded */
chip->dsp_code = NULL; /* Current DSP code not loaded */
chip->asic_loaded = false;
memset(chip->comm_page, 0, sizeof(struct comm_page));
/* Init the comm page */
chip->comm_page->comm_size =
cpu_to_le32(sizeof(struct comm_page));
chip->comm_page->handshake = cpu_to_le32(0xffffffff);
chip->comm_page->midi_out_free_count =
cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE);
chip->comm_page->sample_rate = cpu_to_le32(44100);
/* Set line levels so we don't blast any inputs on startup */
memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE);
memset(chip->comm_page->vmixer, ECHOGAIN_MUTED, VMIXER_ARRAY_SIZE);
return0;
}
/* This function initializes the chip structure with default values, ie. all *mutedandinternalclocksource.ThenitcopiesthesettingstotheDSP. *ThisMUSTbecalledaftertheDSPisupandrunning!
*/ staticint init_line_levels(struct echoaudio *chip)
{
memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain));
memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain));
memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain));
memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain));
chip->input_clock = ECHO_CLOCK_INTERNAL;
chip->output_clock = ECHO_CLOCK_WORD;
chip->sample_rate = 44100; return restore_dsp_rettings(chip);
}
/* This is low level part of the interrupt handler. Itreturns-1iftheIRQisnotours,orN>=0ifitis,whereNisthenumber
of midi data in the input queue. */ staticint service_irq(struct echoaudio *chip)
{ int st;
/* Read the DSP status register and see if this DSP generated this interrupt */ if (get_dsp_register(chip, CHI32_STATUS_REG) & CHI32_STATUS_IRQ) {
st = 0; #ifdef ECHOCARD_HAS_MIDI /* Get and parse midi data if present */ if (chip->comm_page->midi_input[0]) /* The count is at index 0 */
st = midi_service_irq(chip); /* Returns how many midi bytes we received */ #endif /* Clear the hardware interrupt */
chip->comm_page->midi_input[0] = 0;
send_vector(chip, DSP_VC_ACK_INT); return st;
} return -1;
}
/* allocate_pipes is used to reserve audio pipes for your exclusive use.
The call will fail if some pipes are already allocated. */ staticint allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe, int pipe_index, int interleave)
{ int i;
u32 channel_mask;
/* The counter register is where the DSP writes the 32 bit DMA positionforapipe.TheDSPisconstantlyupdatingthisvalueas
it moves data. The DMA counter is in units of bytes, not samples. */
pipe->dma_counter = (__le32 *)&chip->comm_page->position[pipe_index];
*pipe->dma_counter = 0; return pipe_index;
}
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.