?? ymfpci.c
字號:
state->format.voices == 2, state->format.rate, ymf_pcm_format_width(state->format.format) == 16, virt_to_bus(ypcm->dmabuf.rawbuf), ypcm->dmabuf.dmasize, ypcm->spdif); } return 0;}static int ymf_capture_prepare(struct ymf_state *state){ ymfpci_t *unit = state->unit; struct ymf_pcm *ypcm = &state->rpcm; ymfpci_capture_bank_t * bank; /* XXX This is confusing, gotta rename one of them banks... */ int nbank; /* flip-flop bank */ int cbank; /* input [super-]bank */ struct ymf_capture *cap; u32 rate, format; if (ypcm->capture_bank_number == -1) { if (ymf_capture_alloc(unit, &cbank) != 0) return -EBUSY; ypcm->capture_bank_number = cbank; cap = &unit->capture[cbank]; cap->bank = unit->bank_capture[cbank][0]; cap->ypcm = ypcm; ymfpci_hw_start(unit); } // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream); // frag_size is replaced with nonfragged byte-aligned rolling buffer rate = ((48000 * 4096) / state->format.rate) - 1; format = 0; if (state->format.voices == 2) format |= 2; if (ymf_pcm_format_width(state->format.format) == 8) format |= 1; switch (ypcm->capture_bank_number) { case 0: ymfpci_writel(unit, YDSXGR_RECFORMAT, format); ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate); break; case 1: ymfpci_writel(unit, YDSXGR_ADCFORMAT, format); ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate); break; } for (nbank = 0; nbank < 2; nbank++) { bank = unit->bank_capture[ypcm->capture_bank_number][nbank]; bank->base = virt_to_bus(ypcm->dmabuf.rawbuf); // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift; bank->loop_end = ypcm->dmabuf.dmasize; bank->start = 0; bank->num_of_loops = 0; }#if 0 /* s/pdif */ if (state->digital.dig_valid) /*state->digital.type == SND_PCM_DIG_AES_IEC958*/ ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS, state->digital.dig_status[0] | (state->digital.dig_status[1] << 8));#endif return 0;}void ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs){ ymfpci_t *codec = dev_id; u32 status, nvoice, mode; struct ymf_voice *voice; struct ymf_capture *cap; status = ymfpci_readl(codec, YDSXGR_STATUS); if (status & 0x80000000) { codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1; spin_lock(&codec->voice_lock); for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) { voice = &codec->voices[nvoice]; if (voice->use) ymf_pcm_interrupt(codec, voice); } for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) { cap = &codec->capture[nvoice]; if (cap->use) ymf_cap_interrupt(codec, cap); } spin_unlock(&codec->voice_lock); spin_lock(&codec->reg_lock); ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000); mode = ymfpci_readl(codec, YDSXGR_MODE) | 2; ymfpci_writel(codec, YDSXGR_MODE, mode); spin_unlock(&codec->reg_lock); } status = ymfpci_readl(codec, YDSXGR_INTFLAG); if (status & 1) { /* timer handler */ ymfpci_writel(codec, YDSXGR_INTFLAG, ~0); }}static void ymf_pcm_free_substream(struct ymf_pcm *ypcm){ unsigned long flags; struct ymf_unit *unit; unit = ypcm->state->unit; if (ypcm->type == PLAYBACK_VOICE) { spin_lock_irqsave(&unit->voice_lock, flags); if (ypcm->voices[1]) ymfpci_voice_free(unit, ypcm->voices[1]); if (ypcm->voices[0]) ymfpci_voice_free(unit, ypcm->voices[0]); spin_unlock_irqrestore(&unit->voice_lock, flags); } else { if (ypcm->capture_bank_number != -1) { unit->capture[ypcm->capture_bank_number].use = 0; ypcm->capture_bank_number = -1; ymfpci_hw_stop(unit); } }}static struct ymf_state *ymf_state_alloc(ymfpci_t *unit){ struct ymf_pcm *ypcm; struct ymf_state *state; if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) { goto out0; } memset(state, 0, sizeof(struct ymf_state)); ypcm = &state->wpcm; ypcm->state = state; ypcm->type = PLAYBACK_VOICE; ypcm->capture_bank_number = -1; init_waitqueue_head(&ypcm->dmabuf.wait); ypcm = &state->rpcm; ypcm->state = state; ypcm->type = CAPTURE_AC97; ypcm->capture_bank_number = -1; init_waitqueue_head(&ypcm->dmabuf.wait); state->unit = unit; state->format.format = AFMT_U8; state->format.rate = 8000; state->format.voices = 1; ymf_pcm_update_shift(&state->format); return state;out0: return NULL;}/* AES/IEC958 channel status bits */#define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */#define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */#define SND_PCM_AES0_PRO_EMPHASIS (7<<2) /* mask - emphasis */#define SND_PCM_AES0_PRO_EMPHASIS_NOTID (0<<2) /* emphasis not indicated */#define SND_PCM_AES0_PRO_EMPHASIS_NONE (1<<2) /* none emphasis */#define SND_PCM_AES0_PRO_EMPHASIS_5015 (3<<2) /* 50/15us emphasis */#define SND_PCM_AES0_PRO_EMPHASIS_CCITT (7<<2) /* CCITT J.17 emphasis */#define SND_PCM_AES0_PRO_FREQ_UNLOCKED (1<<5) /* source sample frequency: 0 = locked, 1 = unlocked */#define SND_PCM_AES0_PRO_FS (3<<6) /* mask - sample frequency */#define SND_PCM_AES0_PRO_FS_NOTID (0<<6) /* fs not indicated */#define SND_PCM_AES0_PRO_FS_44100 (1<<6) /* 44.1kHz */#define SND_PCM_AES0_PRO_FS_48000 (2<<6) /* 48kHz */#define SND_PCM_AES0_PRO_FS_32000 (3<<6) /* 32kHz */#define SND_PCM_AES0_CON_NOT_COPYRIGHT (1<<2) /* 0 = copyright, 1 = not copyright */#define SND_PCM_AES0_CON_EMPHASIS (7<<3) /* mask - emphasis */#define SND_PCM_AES0_CON_EMPHASIS_NONE (0<<3) /* none emphasis */#define SND_PCM_AES0_CON_EMPHASIS_5015 (1<<3) /* 50/15us emphasis */#define SND_PCM_AES0_CON_MODE (3<<6) /* mask - mode */#define SND_PCM_AES1_PRO_MODE (15<<0) /* mask - channel mode */#define SND_PCM_AES1_PRO_MODE_NOTID (0<<0) /* not indicated */#define SND_PCM_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */#define SND_PCM_AES1_PRO_MODE_SINGLE (4<<0) /* single channel */#define SND_PCM_AES1_PRO_MODE_TWO (8<<0) /* two channels */#define SND_PCM_AES1_PRO_MODE_PRIMARY (12<<0) /* primary/secondary */#define SND_PCM_AES1_PRO_MODE_BYTE3 (15<<0) /* vector to byte 3 */#define SND_PCM_AES1_PRO_USERBITS (15<<4) /* mask - user bits */#define SND_PCM_AES1_PRO_USERBITS_NOTID (0<<4) /* not indicated */#define SND_PCM_AES1_PRO_USERBITS_192 (8<<4) /* 192-bit structure */#define SND_PCM_AES1_PRO_USERBITS_UDEF (12<<4) /* user defined application */#define SND_PCM_AES1_CON_CATEGORY 0x7f#define SND_PCM_AES1_CON_GENERAL 0x00#define SND_PCM_AES1_CON_EXPERIMENTAL 0x40#define SND_PCM_AES1_CON_SOLIDMEM_MASK 0x0f#define SND_PCM_AES1_CON_SOLIDMEM_ID 0x08#define SND_PCM_AES1_CON_BROADCAST1_MASK 0x07#define SND_PCM_AES1_CON_BROADCAST1_ID 0x04#define SND_PCM_AES1_CON_DIGDIGCONV_MASK 0x07#define SND_PCM_AES1_CON_DIGDIGCONV_ID 0x02#define SND_PCM_AES1_CON_ADC_COPYRIGHT_MASK 0x1f#define SND_PCM_AES1_CON_ADC_COPYRIGHT_ID 0x06#define SND_PCM_AES1_CON_ADC_MASK 0x1f#define SND_PCM_AES1_CON_ADC_ID 0x16#define SND_PCM_AES1_CON_BROADCAST2_MASK 0x0f#define SND_PCM_AES1_CON_BROADCAST2_ID 0x0e#define SND_PCM_AES1_CON_LASEROPT_MASK 0x07#define SND_PCM_AES1_CON_LASEROPT_ID 0x01#define SND_PCM_AES1_CON_MUSICAL_MASK 0x07#define SND_PCM_AES1_CON_MUSICAL_ID 0x05#define SND_PCM_AES1_CON_MAGNETIC_MASK 0x07#define SND_PCM_AES1_CON_MAGNETIC_ID 0x03#define SND_PCM_AES1_CON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x00)#define SND_PCM_AES1_CON_NON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x08)#define SND_PCM_AES1_CON_PCM_CODER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x00)#define SND_PCM_AES1_CON_SAMPLER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x20)#define SND_PCM_AES1_CON_MIXER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x10)#define SND_PCM_AES1_CON_RATE_CONVERTER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x18)#define SND_PCM_AES1_CON_SYNTHESIZER (SND_PCM_AES1_CON_MUSICAL_ID|0x00)#define SND_PCM_AES1_CON_MICROPHONE (SND_PCM_AES1_CON_MUSICAL_ID|0x08)#define SND_PCM_AES1_CON_DAT (SND_PCM_AES1_CON_MAGNETIC_ID|0x00)#define SND_PCM_AES1_CON_VCR (SND_PCM_AES1_CON_MAGNETIC_ID|0x08)#define SND_PCM_AES1_CON_ORIGINAL (1<<7) /* this bits depends on the category code */#define SND_PCM_AES2_PRO_SBITS (7<<0) /* mask - sample bits */#define SND_PCM_AES2_PRO_SBITS_20 (2<<0) /* 20-bit - coordination */#define SND_PCM_AES2_PRO_SBITS_24 (4<<0) /* 24-bit - main audio */#define SND_PCM_AES2_PRO_SBITS_UDEF (6<<0) /* user defined application */#define SND_PCM_AES2_PRO_WORDLEN (7<<3) /* mask - source word length */#define SND_PCM_AES2_PRO_WORDLEN_NOTID (0<<3) /* not indicated */#define SND_PCM_AES2_PRO_WORDLEN_22_18 (2<<3) /* 22-bit or 18-bit */#define SND_PCM_AES2_PRO_WORDLEN_23_19 (4<<3) /* 23-bit or 19-bit */#define SND_PCM_AES2_PRO_WORDLEN_24_20 (5<<3) /* 24-bit or 20-bit */#define SND_PCM_AES2_PRO_WORDLEN_20_16 (6<<3) /* 20-bit or 16-bit */#define SND_PCM_AES2_CON_SOURCE (15<<0) /* mask - source number */#define SND_PCM_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */#define SND_PCM_AES2_CON_CHANNEL (15<<4) /* mask - channel number */#define SND_PCM_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */#define SND_PCM_AES3_CON_FS (15<<0) /* mask - sample frequency */#define SND_PCM_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */#define SND_PCM_AES3_CON_FS_48000 (2<<0) /* 48kHz */#define SND_PCM_AES3_CON_FS_32000 (3<<0) /* 32kHz */#define SND_PCM_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */#define SND_PCM_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */#define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */#define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch *//* * User interface *//* * in this loop, dmabuf.count signifies the amount of data that is * waiting to be copied to the user's buffer. it is filled by the dma * machine and drained by this loop. */static ssize_tymf_read(struct file *file, char *buffer, size_t count, loff_t *ppos){ struct ymf_state *state = (struct ymf_state *)file->private_data; struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf; struct ymf_unit *unit = state->unit; DECLARE_WAITQUEUE(waita, current); ssize_t ret; unsigned long flags; unsigned int swptr; int cnt; /* This many to go in this revolution */ if (ppos != &file->f_pos) return -ESPIPE; if (dmabuf->mapped) return -ENXIO; if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) return ret; ret = 0; add_wait_queue(&dmabuf->wait, &waita); set_current_state(TASK_INTERRUPTIBLE); while (count > 0) { spin_lock_irqsave(&unit->reg_lock, flags); if (unit->suspended) { spin_unlock_irqrestore(&unit->reg_lock, flags); schedule(); set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { if (!ret) ret = -EAGAIN; break; } continue; } swptr = dmabuf->swptr; cnt = dmabuf->dmasize - swptr; if (dmabuf->count < cnt) cnt = dmabuf->count; spin_unlock_irqrestore(&unit->reg_lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { unsigned long tmo; /* buffer is empty, start the dma machine and wait for data to be recorded */ spin_lock_irqsave(&state->unit->reg_lock, flags); if (!state->rpcm.running) { ymf_capture_trigger(state->unit, &state->rpcm, 1); } spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; break; } /* This isnt strictly right for the 810 but it'll do */ tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2); tmo >>= state->format.shift; /* There are two situations when sleep_on_timeout returns, one is when the interrupt is serviced correctly and the process is waked up by ISR ON TIME. Another is when timeout is expired, which means that either interrupt is NOT serviced correctly (pending interrupt) or it is TOO LATE for the process to be scheduled to run (scheduler latency) which results in a (potential) buffer overrun. And worse, there is NOTHING we can do to prevent it. */ tmo = schedule_timeout(tmo); spin_lock_irqsave(&state->unit->reg_lock, flags); set_current_state(TASK_INTERRUPTIBLE); if (tmo == 0 && dmabuf->count == 0) { printk(KERN_ERR "ymfpci%d: recording schedule timeout, " "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", state->unit->dev_audio, dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, dmabuf->hwptr, dmabuf->swptr); } spin_unlock_irqrestore(&state->unit->reg_lock, flags); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; break; } continue; } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; break; } swptr = (swptr + cnt) % dmabuf->dmasize; spin_lock_irqsave(&unit->reg_lock, flags); if (unit->suspended) { spin_unlock_irqrestore(&unit->reg_lock, flags); continue; } dmabuf->swptr = swptr; dmabuf->count -= cnt; // spin_unlock_irqrestore(&unit->reg_lock, flags); count -= cnt; buffer += cnt; ret += cnt; // spin_lock_irqsave(&unit->reg_lock, flags); if (!state->rpcm.running) { ymf_capture_trigger(unit, &state->rpcm, 1); } spin_unlock_irqrestore(&unit->reg_lock, flags); } set_current_state(TASK_RUNNING); remove_wait_queue(&dmabuf->wait, &waita); return ret;}static ssize_tymf_write(struct file *file, const char *buffer, size_t count, loff_t *ppos){ struct ymf_state *state = (struct ymf_state *)file->private_data; struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf; struct ymf_unit *unit = state->unit; DECLARE_WAITQUEUE(waita, current); ssize_t ret; unsigned long flags; unsigned int swptr; int cnt; /* This many to go in this revolution */ int redzone; int delay; YMFDBGW("ymf_write: count %d\n", count); if (ppos != &file->f_pos) return -ESPIPE; if (dmabuf->mapped) return -ENXIO; if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) return ret; ret = 0; /* * Alan's cs46xx works without a red zone - marvel of ingenuity. * We are not so brilliant... Red zone does two things: * 1. allows for safe start after a pause as we have no way * to know what the actual, relentlessly advancing, hwptr is. * 2. makes computations in ymf_pcm_interrupt simpler. */ redzone = ymf_calc_lend(state->format.rate) << state->format.shift; redzone *= 3; /* 2 redzone + 1 possible uncertainty reserve. */ add_wait_queue(&dmabuf->wait, &waita); set_current_state(TASK_INTERRUPTIBLE); while (count > 0) { spin_lock_irqsave(&unit->reg_lock, flags); if (unit->suspended) { spin_unlock_irqrestore(&unit->reg_lock, flags); schedule(); set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { if (!ret) ret = -EAGAIN; break; } continue; } if (dmabuf->count < 0) { printk(KERN_ERR "ymf_write: count %d, was legal in cs46xx\n", dmabuf->count); dmabuf->count = 0; } if (dmabuf->count == 0) { swptr = dmabuf->hwptr; if (state->wpcm.running) { /* * Add uncertainty reserve. */ cnt = ymf_calc_lend(state->format.rate); cnt <<= state->format.shift; if ((swptr += cnt) >= dmabuf->dmasize) { swptr -= dmabuf->dmasize; } } dmabuf->swptr = swptr; } else { /* * XXX This is not right if dmabuf->count is small - * about 2*x frame size or less. We cannot count on * on appending and not causing an artefact. * Should use a variation of the count==0 case above. */ swptr = dmabuf->swptr; } cnt = dmabuf->dmasize - swptr; if (dmabuf->count + cnt > dmabuf->dmasize - redzone) cnt = (dmabuf->dmasize - redzone) - dmabuf->count; spin_unlock_irqrestore(&unit->reg_lock, flags); if (cnt > count) cnt = count; if (cnt <= 0) { YMFDBGW("ymf_write: full, count %d swptr %d\n", dmabuf->count, dmabuf->swptr); /* * buffer is full, start the dma machine and * wait for data to be played */ spin_lock_irqsave(&unit->reg_lock, flags); if (!state->wpcm.running) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -