// ---------------------------------------------------------------------------- // Record/Play Buffer Allocation Method. If K1212_LARGEALLOC is defined all // buffers are alocated as a large piece inside KorgSharedBuffer. // ---------------------------------------------------------------------------- //#define K1212_LARGEALLOC 1
// ---------------------------------------------------------------------------- // Valid states of the Korg 1212 I/O card. // ---------------------------------------------------------------------------- enum CardState {
K1212_STATE_NONEXISTENT, // there is no card here
K1212_STATE_UNINITIALIZED, // the card is awaiting DSP download
K1212_STATE_DSP_IN_PROCESS, // the card is currently downloading its DSP code
K1212_STATE_DSP_COMPLETE, // the card has finished the DSP download
K1212_STATE_READY, // the card can be opened by an application. Any application // requests prior to this state should fail. Only an open // request can be made at this state.
K1212_STATE_OPEN, // an application has opened the card
K1212_STATE_SETUP, // the card has been setup for play
K1212_STATE_PLAYING, // the card is playing
K1212_STATE_MONITOR, // the card is in the monitor mode
K1212_STATE_CALIBRATING, // the card is currently calibrating
K1212_STATE_ERRORSTOP, // the card has stopped itself because of an error and we // are in the process of cleaning things up.
K1212_STATE_MAX_STATE // state values of this and beyond are invalid
};
// ---------------------------------------------------------------------------- // The following enumeration defines the constants written to the card's // host-to-card doorbell to initiate a command. // ---------------------------------------------------------------------------- enum korg1212_dbcnst {
K1212_DB_RequestForData = 0, // sent by the card to request a buffer fill.
K1212_DB_TriggerPlay = 1, // starts playback/record on the card.
K1212_DB_SelectPlayMode = 2, // select monitor, playback setup, or stop.
K1212_DB_ConfigureBufferMemory = 3, // tells card where the host audio buffers are.
K1212_DB_RequestAdatTimecode = 4, // asks the card for the latest ADAT timecode value.
K1212_DB_SetClockSourceRate = 5, // sets the clock source and rate for the card.
K1212_DB_ConfigureMiscMemory = 6, // tells card where other buffers are.
K1212_DB_TriggerFromAdat = 7, // tells card to trigger from Adat at a specific // timecode value.
K1212_DB_DMAERROR = 0x80, // DMA Error - the PCI bus is congestioned.
K1212_DB_CARDSTOPPED = 0x81, // Card has stopped by user request.
K1212_DB_RebootCard = 0xA0, // instructs the card to reboot.
K1212_DB_BootFromDSPPage4 = 0xA4, // instructs the card to boot from the DSP microcode // on page 4 (local page to card).
K1212_DB_DSPDownloadDone = 0xAE, // sent by the card to indicate the download has // completed.
K1212_DB_StartDSPDownload = 0xAF // tells the card to download its DSP firmware.
};
// ---------------------------------------------------------------------------- // The following enumeration defines return codes // to the Korg 1212 I/O driver. // ---------------------------------------------------------------------------- enum snd_korg1212rc {
K1212_CMDRET_Success = 0, // command was successfully placed
K1212_CMDRET_DIOCFailure, // the DeviceIoControl call failed
K1212_CMDRET_PMFailure, // the protected mode call failed
K1212_CMDRET_FailUnspecified, // unspecified failure
K1212_CMDRET_FailBadState, // the specified command can not be given in // the card's current state. (or the wave device's // state)
K1212_CMDRET_CardUninitialized, // the card is uninitialized and cannot be used
K1212_CMDRET_BadIndex, // an out of range card index was specified
K1212_CMDRET_BadHandle, // an invalid card handle was specified
K1212_CMDRET_NoFillRoutine, // a play request has been made before a fill routine set
K1212_CMDRET_FillRoutineInUse, // can't set a new fill routine while one is in use
K1212_CMDRET_NoAckFromCard, // the card never acknowledged a command
K1212_CMDRET_BadParams, // bad parameters were provided by the caller
K1212_CMDRET_BadDevice, // the specified wave device was out of range
K1212_CMDRET_BadFormat // the specified wave format is unsupported
};
// ---------------------------------------------------------------------------- // The following enumeration defines the constants used to select the play // mode for the card in the SelectPlayMode command. // ---------------------------------------------------------------------------- enum PlayModeSelector {
K1212_MODE_SetupPlay = 0x00000001, // provides card with pre-play information
K1212_MODE_MonitorOn = 0x00000002, // tells card to turn on monitor mode
K1212_MODE_MonitorOff = 0x00000004, // tells card to turn off monitor mode
K1212_MODE_StopPlay = 0x00000008 // stops playback on the card
};
// ---------------------------------------------------------------------------- // The following enumeration defines the constants used to select the monitor // mode for the card in the SetMonitorMode command. // ---------------------------------------------------------------------------- enum MonitorModeSelector {
K1212_MONMODE_Off = 0, // tells card to turn off monitor mode
K1212_MONMODE_On // tells card to turn on monitor mode
};
#define MAILBOX0_OFFSET 0x40 // location of mailbox 0 relative to base address #define MAILBOX1_OFFSET 0x44 // location of mailbox 1 relative to base address #define MAILBOX2_OFFSET 0x48 // location of mailbox 2 relative to base address #define MAILBOX3_OFFSET 0x4c // location of mailbox 3 relative to base address #define OUT_DOORBELL_OFFSET 0x60 // location of PCI to local doorbell #define IN_DOORBELL_OFFSET 0x64 // location of local to PCI doorbell #define STATUS_REG_OFFSET 0x68 // location of interrupt control/status register #define PCI_CONTROL_OFFSET 0x6c // location of the EEPROM, PCI, User I/O, init control // register #define SENS_CONTROL_OFFSET 0x6e // location of the input sensitivity setting register. // this is the upper word of the PCI control reg. #define DEV_VEND_ID_OFFSET 0x70 // location of the device and vendor ID register
#define MAX_COMMAND_RETRIES 5 // maximum number of times the driver will attempt // to send a command before giving up. #define COMMAND_ACK_MASK 0x8000 // the MSB is set in the command acknowledgment from // the card. #define DOORBELL_VAL_MASK 0x00FF // the doorbell value is one byte
// ----------------------------------------------------------------- // the following bits are used for controlling interrupts in the // interrupt control/status reg // ----------------------------------------------------------------- #define PCI_INT_ENABLE_BIT 0x00000100 #define PCI_DOORBELL_INT_ENABLE_BIT 0x00000200 #define LOCAL_INT_ENABLE_BIT 0x00010000 #define LOCAL_DOORBELL_INT_ENABLE_BIT 0x00020000 #define LOCAL_DMA1_INT_ENABLE_BIT 0x00080000
// ----------------------------------------------------------------- // the following bits are defined for the PCI command register // ----------------------------------------------------------------- #define PCI_CMD_MEM_SPACE_ENABLE_BIT 0x0002 #define PCI_CMD_IO_SPACE_ENABLE_BIT 0x0001 #define PCI_CMD_BUS_MASTER_ENABLE_BIT 0x0004
// ----------------------------------------------------------------- // the following bits are defined for the PCI status register // ----------------------------------------------------------------- #define PCI_STAT_PARITY_ERROR_BIT 0x8000 #define PCI_STAT_SYSTEM_ERROR_BIT 0x4000 #define PCI_STAT_MASTER_ABORT_RCVD_BIT 0x2000 #define PCI_STAT_TARGET_ABORT_RCVD_BIT 0x1000 #define PCI_STAT_TARGET_ABORT_SENT_BIT 0x0800
// ------------------------------------------------------------------------ // the following constants are used in setting the 1212 I/O card's input // sensitivity. // ------------------------------------------------------------------------ #define SET_SENS_LOCALINIT_BITPOS 15 #define SET_SENS_DATA_BITPOS 10 #define SET_SENS_CLOCK_BITPOS 8 #define SET_SENS_LOADSHIFT_BITPOS 0
// -------------------------------------------------------------------------- // WaitRTCTicks // // This function waits the specified number of real time clock ticks. // According to the DDK, each tick is ~0.8 microseconds. // The defines following the function declaration can be used for the // numTicksToWait parameter. // -------------------------------------------------------------------------- #define ONE_RTC_TICK 1 #define SENSCLKPULSE_WIDTH 4 #define LOADSHIFT_DELAY 4 #define INTERCOMMAND_DELAY 40 #define STOPCARD_DELAY 300 // max # RTC ticks for the card to stop once we write // the command register. (could be up to 180 us) #define COMMAND_ACK_DELAY 13 // number of RTC ticks to wait for an acknowledgement // from the card after sending a command.
enum ClockSourceIndex {
K1212_CLKIDX_AdatAt44_1K = 0, // selects source as ADAT at 44.1 kHz
K1212_CLKIDX_AdatAt48K, // selects source as ADAT at 48 kHz
K1212_CLKIDX_WordAt44_1K, // selects source as S/PDIF at 44.1 kHz
K1212_CLKIDX_WordAt48K, // selects source as S/PDIF at 48 kHz
K1212_CLKIDX_LocalAt44_1K, // selects source as local clock at 44.1 kHz
K1212_CLKIDX_LocalAt48K, // selects source as local clock at 48 kHz
K1212_CLKIDX_Invalid // used to check validity of the index
};
enum ClockSourceType {
K1212_CLKIDX_Adat = 0, // selects source as ADAT
K1212_CLKIDX_Word, // selects source as S/PDIF
K1212_CLKIDX_Local // selects source as local clock
};
struct KorgAudioFrame {
u16 frameData16[k16BitChannels]; /* channels 0-9 use 16 bit samples */
u32 frameData32[k32BitChannels]; /* channels 10-11 use 32 bits - only 20 are sent across S/PDIF */
u32 timeCodeVal; /* holds the ADAT timecode value */
};
u32 __iomem * statusRegPtr; // address of the interrupt status/control register
u32 __iomem * outDoorbellPtr; // address of the host->card doorbell register
u32 __iomem * inDoorbellPtr; // address of the card->host doorbell register
u32 __iomem * mailbox0Ptr; // address of mailbox 0 on the card
u32 __iomem * mailbox1Ptr; // address of mailbox 1 on the card
u32 __iomem * mailbox2Ptr; // address of mailbox 2 on the card
u32 __iomem * mailbox3Ptr; // address of mailbox 3 on the card
u32 __iomem * controlRegPtr; // address of the EEPROM, PCI, I/O, Init ctrl reg
u16 __iomem * sensRegPtr; // address of the sensitivity setting register
u32 __iomem * idRegPtr; // address of the device and vendor ID registers
size_t periodsize; int channels; int currentBuffer;
enum CardState cardState; int running; int idleMonitorOn; // indicates whether the card is in idle monitor mode.
u32 cmdRetryCount; // tracks how many times we have retried sending to the card.
enum ClockSourceIndex clkSrcRate; // sample rate and clock source
staticconst u16 ClockSourceSelector[] = {
0x8000, // selects source as ADAT at 44.1 kHz
0x0000, // selects source as ADAT at 48 kHz
0x8001, // selects source as S/PDIF at 44.1 kHz
0x0001, // selects source as S/PDIF at 48 kHz
0x8002, // selects source as local clock at 44.1 kHz
0x0002 // selects source as local clock at 48 kHz
};
// -------------------------------------------------------------- // the reboot command will not give an acknowledgement. // -------------------------------------------------------------- if ( doorbellVal == K1212_DB_RebootCard ||
doorbellVal == K1212_DB_BootFromDSPPage4 ||
doorbellVal == K1212_DB_StartDSPDownload ) {
rc = K1212_CMDRET_Success; break;
}
// -------------------------------------------------------------- // See if the card acknowledged the command. Wait a bit, then // read in the low word of mailbox3. If the MSB is set and the // low byte is equal to the doorbell value, then it ack'd. // --------------------------------------------------------------
udelay(COMMAND_ACK_DELAY);
mailBox3Lo = readl(korg1212->mailbox3Ptr); if (mailBox3Lo & COMMAND_ACK_MASK) { if ((mailBox3Lo & DOORBELL_VAL_MASK) == (doorbellVal & DOORBELL_VAL_MASK)) {
K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: Card <- Success\n");
rc = K1212_CMDRET_Success; break;
}
}
}
korg1212->cmdRetryCount += retryCount;
staticint snd_korg1212_WriteADCSensitivity(struct snd_korg1212 *korg1212)
{ struct SensBits sensVals; int bitPosition; int channel; int clkIs48K; int monModeSet;
u16 controlValue; // this keeps the current value to be written to // the card's eeprom control register.
u16 count; unsignedlong flags;
// ---------------------------------------------------------------------------- // initialize things. The local init bit is always set when writing to the // card's control register. // ----------------------------------------------------------------------------
controlValue = 0;
SetBitInWord(&controlValue, SET_SENS_LOCALINIT_BITPOS); // init the control value
// ---------------------------------------------------------------------------- // make sure the card is not in monitor mode when we do this update. // ---------------------------------------------------------------------------- if (korg1212->cardState == K1212_STATE_MONITOR || korg1212->idleMonitorOn) {
monModeSet = 1;
snd_korg1212_SendStopAndWait(korg1212);
} else
monModeSet = 0;
spin_lock_irqsave(&korg1212->lock, flags);
// ---------------------------------------------------------------------------- // we are about to send new values to the card, so clear the new values queued // flag. Also, clear out mailbox 3, so we don't lockup. // ----------------------------------------------------------------------------
writel(0, korg1212->mailbox3Ptr);
udelay(LOADSHIFT_DELAY);
// ---------------------------------------------------------------------------- // determine whether we are running a 48K or 44.1K clock. This info is used // later when setting the SPDIF FF after the volume has been shifted in. // ---------------------------------------------------------------------------- switch (korg1212->clkSrcRate) { case K1212_CLKIDX_AdatAt44_1K: case K1212_CLKIDX_WordAt44_1K: case K1212_CLKIDX_LocalAt44_1K:
clkIs48K = 0; break;
case K1212_CLKIDX_WordAt48K: case K1212_CLKIDX_AdatAt48K: case K1212_CLKIDX_LocalAt48K: default:
clkIs48K = 1; break;
}
// ---------------------------------------------------------------------------- // start the update. Setup the bit structure and then shift the bits. // ----------------------------------------------------------------------------
sensVals.l.v.leftChanId = SET_SENS_LEFTCHANID;
sensVals.r.v.rightChanId = SET_SENS_RIGHTCHANID;
sensVals.l.v.leftChanVal = korg1212->leftADCInSens;
sensVals.r.v.rightChanVal = korg1212->rightADCInSens;
// ---------------------------------------------------------------------------- // now start shifting the bits in. Start with the left channel then the right. // ---------------------------------------------------------------------------- for (channel = 0; channel < 2; channel++) {
// ---------------------------------------------------------------------------- // Bring the load/shift line low, then wait - the spec says >150ns from load/ // shift low to the first rising edge of the clock. // ----------------------------------------------------------------------------
ClearBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // load/shift goes low
udelay(LOADSHIFT_DELAY);
for (bitPosition = 15; bitPosition >= 0; bitPosition--) { // for all the bits if (channel == 0) { if (sensVals.l.leftSensBits & (0x0001 << bitPosition))
SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS); // data bit set high else
ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS); // data bit set low
} else { if (sensVals.r.rightSensBits & (0x0001 << bitPosition))
SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS); // data bit set high else
ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS); // data bit set low
}
// ---------------------------------------------------------------------------- // finish up SPDIF for left. Bring the load/shift line high, then write a one // bit if the clock rate is 48K otherwise write 0. // ----------------------------------------------------------------------------
ClearBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
SetBitInWord(&controlValue, SET_SENS_LOADSHIFT_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // load shift goes high - clk low
udelay(SENSCLKPULSE_WIDTH);
if (clkIs48K)
SetBitInWord(&controlValue, SET_SENS_DATA_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // set/clear data bit
udelay(ONE_RTC_TICK);
SetBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes high
udelay(SENSCLKPULSE_WIDTH);
ClearBitInWord(&controlValue, SET_SENS_CLOCK_BITPOS);
writew(controlValue, korg1212->sensRegPtr); // clock goes low
udelay(SENSCLKPULSE_WIDTH);
}
// ---------------------------------------------------------------------------- // The update is complete. Set a timeout. This is the inter-update delay. // Also, if the card was in monitor mode, restore it. // ---------------------------------------------------------------------------- for (count = 0; count < 10; count++)
udelay(SENSCLKPULSE_WIDTH);
if (monModeSet) { int rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode,
K1212_MODE_MonitorOn, 0, 0, 0); if (rc)
K1212_DEBUG_PRINTK("K1212_DEBUG: WriteADCSensivity - RC = %d [%s]\n",
rc, stateName[korg1212->cardState]);
}
spin_unlock_irqrestore(&korg1212->lock, flags);
return 1;
}
staticvoid snd_korg1212_OnDSPDownloadComplete(struct snd_korg1212 *korg1212)
{ int channel, rc;
K1212_DEBUG_PRINTK("K1212_DEBUG: DSP download is complete. [%s]\n",
stateName[korg1212->cardState]);
// ---------------------------------------------------- // tell the card to boot // ----------------------------------------------------
rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_BootFromDSPPage4, 0, 0, 0, 0);
if (rc)
K1212_DEBUG_PRINTK("K1212_DEBUG: Boot from Page 4 - RC = %d [%s]\n",
rc, stateName[korg1212->cardState]);
msleep(DSP_BOOT_DELAY_IN_MS);
// -------------------------------------------------------------------------------- // Let the card know where all the buffers are. // --------------------------------------------------------------------------------
rc = snd_korg1212_Send1212Command(korg1212,
K1212_DB_ConfigureBufferMemory,
LowerWordSwap(korg1212->PlayDataPhy),
LowerWordSwap(korg1212->RecDataPhy),
((kNumBuffers * kPlayBufferFrames) / 2), // size given to the card // is based on 2 buffers
0
);
// -------------------------------------------------------------------------------- // Initialize the routing and volume tables, then update the card's state. // --------------------------------------------------------------------------------
udelay(INTERCOMMAND_DELAY);
// ------------------------------------------------------------------------ // the card has stopped by our request. Clear the command word and signal // the semaphore in case someone is waiting for this. // ------------------------------------------------------------------------ case K1212_DB_CARDSTOPPED:
K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: IRQ CSTP count - %ld, %x, [%s].\n",
korg1212->irqcount, doorbellValue,
stateName[korg1212->cardState]);
korg1212->sharedBufferPtr->cardCommand = 0;
korg1212->dsp_stop_processing = 0;
wake_up(&korg1212->wait); break;
if (korg1212->currentBuffer >= kNumBuffers)
korg1212->currentBuffer = 0;
if (!korg1212->running) break;
if (korg1212->capture_substream) {
spin_unlock(&korg1212->lock);
snd_pcm_period_elapsed(korg1212->capture_substream);
spin_lock(&korg1212->lock);
}
if (korg1212->playback_substream) {
spin_unlock(&korg1212->lock);
snd_pcm_period_elapsed(korg1212->playback_substream);
spin_lock(&korg1212->lock);
}
} break;
}
korg1212->inIRQ--;
spin_unlock(&korg1212->lock);
return IRQ_HANDLED;
}
staticint snd_korg1212_downloadDSPCode(struct snd_korg1212 *korg1212)
{ int rc;
K1212_DEBUG_PRINTK("K1212_DEBUG: DSP download is starting... [%s]\n",
stateName[korg1212->cardState]);
// --------------------------------------------------------------- // verify the state of the card before proceeding. // --------------------------------------------------------------- if (korg1212->cardState >= K1212_STATE_DSP_IN_PROCESS) return 1;
staticint snd_korg1212_silence(struct snd_korg1212 *korg1212, int pos, int count, int offset, int size)
{ struct KorgAudioFrame * dst = korg1212->playDataBufsPtr[0].bufferData + pos; int i;
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.