📄 korg1212.c
字号:
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; struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; pid_t capture_pid; pid_t playback_pid; 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 enum ClockSourceType clkSource; // clock source int clkRate; // clock rate int volumePhase[kAudioChannels]; u16 leftADCInSens; // ADC left channel input sensitivity u16 rightADCInSens; // ADC right channel input sensitivity int opencnt; // Open/Close count int setcnt; // SetupForPlay count int playcnt; // TriggerPlay count int errorcnt; // Error Count unsigned long totalerrorcnt; // Total Error Count int dsp_is_loaded; int dsp_stop_is_processed;};MODULE_DESCRIPTION("korg1212");MODULE_LICENSE("GPL");MODULE_SUPPORTED_DEVICE("{{KORG,korg1212}}");static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */module_param_array(index, int, NULL, 0444);MODULE_PARM_DESC(index, "Index value for Korg 1212 soundcard.");module_param_array(id, charp, NULL, 0444);MODULE_PARM_DESC(id, "ID string for Korg 1212 soundcard.");module_param_array(enable, bool, NULL, 0444);MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard.");MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>");static struct pci_device_id snd_korg1212_ids[] __devinitdata = { { .vendor = 0x10b5, .device = 0x906d, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { 0, },};MODULE_DEVICE_TABLE(pci, snd_korg1212_ids);static char *stateName[] = { "Non-existent", "Uninitialized", "DSP download in process", "DSP download complete", "Ready", "Open", "Setup for play", "Playing", "Monitor mode on", "Calibrating", "Invalid"};static char *clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" };static char *clockSourceName[] = { "ADAT at 44.1 kHz", "ADAT at 48 kHz", "S/PDIF at 44.1 kHz", "S/PDIF at 48 kHz", "local clock at 44.1 kHz", "local clock at 48 kHz"};static char *channelName[] = { "ADAT-1", "ADAT-2", "ADAT-3", "ADAT-4", "ADAT-5", "ADAT-6", "ADAT-7", "ADAT-8", "Analog-L", "Analog-R", "SPDIF-L", "SPDIF-R",};static 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};union swap_u32 { unsigned char c[4]; u32 i; };#ifdef SNDRV_BIG_ENDIANstatic u32 LowerWordSwap(u32 swappee)#elsestatic u32 UpperWordSwap(u32 swappee)#endif{ union swap_u32 retVal, swapper; swapper.i = swappee; retVal.c[2] = swapper.c[3]; retVal.c[3] = swapper.c[2]; retVal.c[1] = swapper.c[1]; retVal.c[0] = swapper.c[0]; return retVal.i;}#ifdef SNDRV_BIG_ENDIANstatic u32 UpperWordSwap(u32 swappee)#elsestatic u32 LowerWordSwap(u32 swappee)#endif{ union swap_u32 retVal, swapper; swapper.i = swappee; retVal.c[2] = swapper.c[2]; retVal.c[3] = swapper.c[3]; retVal.c[1] = swapper.c[0]; retVal.c[0] = swapper.c[1]; return retVal.i;}#define SetBitInWord(theWord,bitPosition) (*theWord) |= (0x0001 << bitPosition)#define SetBitInDWord(theWord,bitPosition) (*theWord) |= (0x00000001 << bitPosition)#define ClearBitInWord(theWord,bitPosition) (*theWord) &= ~(0x0001 << bitPosition)#define ClearBitInDWord(theWord,bitPosition) (*theWord) &= ~(0x00000001 << bitPosition)static int snd_korg1212_Send1212Command(struct snd_korg1212 *korg1212, enum korg1212_dbcnst doorbellVal, u32 mailBox0Val, u32 mailBox1Val, u32 mailBox2Val, u32 mailBox3Val){ u32 retryCount; u16 mailBox3Lo; int rc = K1212_CMDRET_Success; if (!korg1212->outDoorbellPtr) { K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: CardUninitialized\n"); return K1212_CMDRET_CardUninitialized; } K1212_DEBUG_PRINTK("K1212_DEBUG: Card <- 0x%08x 0x%08x [%s]\n", doorbellVal, mailBox0Val, stateName[korg1212->cardState]); for (retryCount = 0; retryCount < MAX_COMMAND_RETRIES; retryCount++) { writel(mailBox3Val, korg1212->mailbox3Ptr); writel(mailBox2Val, korg1212->mailbox2Ptr); writel(mailBox1Val, korg1212->mailbox1Ptr); writel(mailBox0Val, korg1212->mailbox0Ptr); writel(doorbellVal, korg1212->outDoorbellPtr); // interrupt the card // -------------------------------------------------------------- // 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; if (retryCount >= MAX_COMMAND_RETRIES) { K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: Card <- NoAckFromCard\n"); rc = K1212_CMDRET_NoAckFromCard; } return rc;}/* spinlock already held */static void snd_korg1212_SendStop(struct snd_korg1212 *korg1212){ if (! korg1212->stop_pending_cnt) { korg1212->sharedBufferPtr->cardCommand = 0xffffffff; /* program the timer */ korg1212->stop_pending_cnt = HZ; korg1212->timer.expires = jiffies + 1; add_timer(&korg1212->timer); }}static void snd_korg1212_SendStopAndWait(struct snd_korg1212 *korg1212){ unsigned long flags; spin_lock_irqsave(&korg1212->lock, flags); korg1212->dsp_stop_is_processed = 0; snd_korg1212_SendStop(korg1212); spin_unlock_irqrestore(&korg1212->lock, flags); wait_event_timeout(korg1212->wait, korg1212->dsp_stop_is_processed, (HZ * 3) / 2);}/* timer callback for checking the ack of stop request */static void snd_korg1212_timer_func(unsigned long data){ struct snd_korg1212 *korg1212 = (struct snd_korg1212 *) data; unsigned long flags; spin_lock_irqsave(&korg1212->lock, flags); if (korg1212->sharedBufferPtr->cardCommand == 0) { /* ack'ed */ korg1212->stop_pending_cnt = 0; korg1212->dsp_stop_is_processed = 1; wake_up(&korg1212->wait); K1212_DEBUG_PRINTK_VERBOSE("K1212_DEBUG: Stop ack'ed [%s]\n", stateName[korg1212->cardState]); } else { if (--korg1212->stop_pending_cnt > 0) { /* reprogram timer */ korg1212->timer.expires = jiffies + 1; add_timer(&korg1212->timer); } else { snd_printd("korg1212_timer_func timeout\n"); korg1212->sharedBufferPtr->cardCommand = 0; korg1212->dsp_stop_is_processed = 1; wake_up(&korg1212->wait); K1212_DEBUG_PRINTK("K1212_DEBUG: Stop timeout [%s]\n", stateName[korg1212->cardState]); } } spin_unlock_irqrestore(&korg1212->lock, flags);}static int snd_korg1212_TurnOnIdleMonitor(struct snd_korg1212 *korg1212){ unsigned long flags; int rc; udelay(INTERCOMMAND_DELAY); spin_lock_irqsave(&korg1212->lock, flags); korg1212->idleMonitorOn = 1; rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, K1212_MODE_MonitorOn, 0, 0, 0); spin_unlock_irqrestore(&korg1212->lock, flags); return rc;}static void snd_korg1212_TurnOffIdleMonitor(struct snd_korg1212 *korg1212){ if (korg1212->idleMonitorOn) { snd_korg1212_SendStopAndWait(korg1212); korg1212->idleMonitorOn = 0; }}static inline void snd_korg1212_setCardState(struct snd_korg1212 * korg1212, enum CardState csState){ korg1212->cardState = csState;}static int snd_korg1212_OpenCard(struct snd_korg1212 * korg1212){ K1212_DEBUG_PRINTK("K1212_DEBUG: OpenCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt); mutex_lock(&korg1212->open_mutex); if (korg1212->opencnt++ == 0) { snd_korg1212_TurnOffIdleMonitor(korg1212); snd_korg1212_setCardState(korg1212, K1212_STATE_OPEN); } mutex_unlock(&korg1212->open_mutex); return 1;}static int snd_korg1212_CloseCard(struct snd_korg1212 * korg1212){ K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard [%s] %d\n", stateName[korg1212->cardState], korg1212->opencnt); mutex_lock(&korg1212->open_mutex); if (--(korg1212->opencnt)) { mutex_unlock(&korg1212->open_mutex); return 0; } if (korg1212->cardState == K1212_STATE_SETUP) { int rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_SelectPlayMode, K1212_MODE_StopPlay, 0, 0, 0); if (rc) K1212_DEBUG_PRINTK("K1212_DEBUG: CloseCard - RC = %d [%s]\n", rc, stateName[korg1212->cardState]); if (rc != K1212_CMDRET_Success) { mutex_unlock(&korg1212->open_mutex); return 0; } } else if (korg1212->cardState > K1212_STATE_SETUP) { snd_korg1212_SendStopAndWait(korg1212); } if (korg1212->cardState > K1212_STATE_READY) { snd_korg1212_TurnOnIdleMonitor(korg1212); snd_korg1212_setCardState(korg1212, K1212_STATE_READY); } mutex_unlock(&korg1212->open_mutex); return 0;}/* spinlock already held */static int snd_korg1212_SetupForPlay(struct snd_korg1212 * korg1212){ int rc; K1212_DEBUG_PRINTK("K1212_DEBUG: SetupForPlay [%s] %d\n", stateName[korg1212->cardState], korg1212->setcnt); if (korg1212->setcnt++) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -