📄 es1968.c
字号:
spin_lock(&chip->reg_lock); __apu_set_register(chip, es->apu[0], 5, es->base[0]); snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]); if (es->mode == ESM_MODE_CAPTURE) { __apu_set_register(chip, es->apu[2], 5, es->base[2]); snd_es1968_trigger_apu(chip, es->apu[2], es->apu_mode[2]); } if (es->fmt & ESS_FMT_STEREO) { __apu_set_register(chip, es->apu[1], 5, es->base[1]); snd_es1968_trigger_apu(chip, es->apu[1], es->apu_mode[1]); if (es->mode == ESM_MODE_CAPTURE) { __apu_set_register(chip, es->apu[3], 5, es->base[3]); snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]); } } spin_unlock(&chip->reg_lock);}static void snd_es1968_pcm_stop(struct es1968 *chip, struct esschan *es){ spin_lock(&chip->reg_lock); snd_es1968_trigger_apu(chip, es->apu[0], 0); snd_es1968_trigger_apu(chip, es->apu[1], 0); if (es->mode == ESM_MODE_CAPTURE) { snd_es1968_trigger_apu(chip, es->apu[2], 0); snd_es1968_trigger_apu(chip, es->apu[3], 0); } spin_unlock(&chip->reg_lock);}/* set the wavecache control reg */static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es, int channel, u32 addr, int capture){ u32 tmpval = (addr - 0x10) & 0xFFF8; if (! capture) { if (!(es->fmt & ESS_FMT_16BIT)) tmpval |= 4; /* 8bit */ if (es->fmt & ESS_FMT_STEREO) tmpval |= 2; /* stereo */ } /* set the wavecache control reg */ wave_set_register(chip, es->apu[channel] << 3, tmpval);#ifdef CONFIG_PM es->wc_map[channel] = tmpval;#endif}static void snd_es1968_playback_setup(struct es1968 *chip, struct esschan *es, struct snd_pcm_runtime *runtime){ u32 pa; int high_apu = 0; int channel, apu; int i, size; unsigned long flags; u32 freq; size = es->dma_size >> es->wav_shift; if (es->fmt & ESS_FMT_STEREO) high_apu++; for (channel = 0; channel <= high_apu; channel++) { apu = es->apu[channel]; snd_es1968_program_wavecache(chip, es, channel, es->memory->buf.addr, 0); /* Offset to PCMBAR */ pa = es->memory->buf.addr; pa -= chip->dma.addr; pa >>= 1; /* words */ pa |= 0x00400000; /* System RAM (Bit 22) */ if (es->fmt & ESS_FMT_STEREO) { /* Enable stereo */ if (channel) pa |= 0x00800000; /* (Bit 23) */ if (es->fmt & ESS_FMT_16BIT) pa >>= 1; } /* base offset of dma calcs when reading the pointer on this left one */ es->base[channel] = pa & 0xFFFF; for (i = 0; i < 16; i++) apu_set_register(chip, apu, i, 0x0000); /* Load the buffer into the wave engine */ apu_set_register(chip, apu, 4, ((pa >> 16) & 0xFF) << 8); apu_set_register(chip, apu, 5, pa & 0xFFFF); apu_set_register(chip, apu, 6, (pa + size) & 0xFFFF); /* setting loop == sample len */ apu_set_register(chip, apu, 7, size); /* clear effects/env.. */ apu_set_register(chip, apu, 8, 0x0000); /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */ apu_set_register(chip, apu, 9, 0xD000); /* clear routing stuff */ apu_set_register(chip, apu, 11, 0x0000); /* dma on, no envelopes, filter to all 1s) */ apu_set_register(chip, apu, 0, 0x400F); if (es->fmt & ESS_FMT_16BIT) es->apu_mode[channel] = ESM_APU_16BITLINEAR; else es->apu_mode[channel] = ESM_APU_8BITLINEAR; if (es->fmt & ESS_FMT_STEREO) { /* set panning: left or right */ /* Check: different panning. On my Canyon 3D Chipset the Channels are swapped. I don't know, about the output to the SPDif Link. Perhaps you have to change this and not the APU Regs 4-5. */ apu_set_register(chip, apu, 10, 0x8F00 | (channel ? 0 : 0x10)); es->apu_mode[channel] += 1; /* stereo */ } else apu_set_register(chip, apu, 10, 0x8F08); } spin_lock_irqsave(&chip->reg_lock, flags); /* clear WP interrupts */ outw(1, chip->io_port + 0x04); /* enable WP ints */ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); spin_unlock_irqrestore(&chip->reg_lock, flags); freq = runtime->rate; /* set frequency */ if (freq > 48000) freq = 48000; if (freq < 4000) freq = 4000; /* hmmm.. */ if (!(es->fmt & ESS_FMT_16BIT) && !(es->fmt & ESS_FMT_STEREO)) freq >>= 1; freq = snd_es1968_compute_rate(chip, freq); /* Load the frequency, turn on 6dB */ snd_es1968_apu_set_freq(chip, es->apu[0], freq); snd_es1968_apu_set_freq(chip, es->apu[1], freq);}static void init_capture_apu(struct es1968 *chip, struct esschan *es, int channel, unsigned int pa, unsigned int bsize, int mode, int route){ int i, apu = es->apu[channel]; es->apu_mode[channel] = mode; /* set the wavecache control reg */ snd_es1968_program_wavecache(chip, es, channel, pa, 1); /* Offset to PCMBAR */ pa -= chip->dma.addr; pa >>= 1; /* words */ /* base offset of dma calcs when reading the pointer on this left one */ es->base[channel] = pa & 0xFFFF; pa |= 0x00400000; /* bit 22 -> System RAM */ /* Begin loading the APU */ for (i = 0; i < 16; i++) apu_set_register(chip, apu, i, 0x0000); /* need to enable subgroups.. and we should probably have different groups for different /dev/dsps.. */ apu_set_register(chip, apu, 2, 0x8); /* Load the buffer into the wave engine */ apu_set_register(chip, apu, 4, ((pa >> 16) & 0xFF) << 8); apu_set_register(chip, apu, 5, pa & 0xFFFF); apu_set_register(chip, apu, 6, (pa + bsize) & 0xFFFF); apu_set_register(chip, apu, 7, bsize); /* clear effects/env.. */ apu_set_register(chip, apu, 8, 0x00F0); /* amplitude now? sure. why not. */ apu_set_register(chip, apu, 9, 0x0000); /* set filter tune, radius, polar pan */ apu_set_register(chip, apu, 10, 0x8F08); /* route input */ apu_set_register(chip, apu, 11, route); /* dma on, no envelopes, filter to all 1s) */ apu_set_register(chip, apu, 0, 0x400F);}static void snd_es1968_capture_setup(struct es1968 *chip, struct esschan *es, struct snd_pcm_runtime *runtime){ int size; u32 freq; unsigned long flags; size = es->dma_size >> es->wav_shift; /* APU assignments: 0 = mono/left SRC 1 = right SRC 2 = mono/left Input Mixer 3 = right Input Mixer */ /* data seems to flow from the codec, through an apu into the 'mixbuf' bit of page, then through the SRC apu and out to the real 'buffer'. ok. sure. */ /* input mixer (left/mono) */ /* parallel in crap, see maestro reg 0xC [8-11] */ init_capture_apu(chip, es, 2, es->mixbuf->buf.addr, ESM_MIXBUF_SIZE/4, /* in words */ ESM_APU_INPUTMIXER, 0x14); /* SRC (left/mono); get input from inputing apu */ init_capture_apu(chip, es, 0, es->memory->buf.addr, size, ESM_APU_SRCONVERTOR, es->apu[2]); if (es->fmt & ESS_FMT_STEREO) { /* input mixer (right) */ init_capture_apu(chip, es, 3, es->mixbuf->buf.addr + ESM_MIXBUF_SIZE/2, ESM_MIXBUF_SIZE/4, /* in words */ ESM_APU_INPUTMIXER, 0x15); /* SRC (right) */ init_capture_apu(chip, es, 1, es->memory->buf.addr + size*2, size, ESM_APU_SRCONVERTOR, es->apu[3]); } freq = runtime->rate; /* Sample Rate conversion APUs don't like 0x10000 for their rate */ if (freq > 47999) freq = 47999; if (freq < 4000) freq = 4000; freq = snd_es1968_compute_rate(chip, freq); /* Load the frequency, turn on 6dB */ snd_es1968_apu_set_freq(chip, es->apu[0], freq); snd_es1968_apu_set_freq(chip, es->apu[1], freq); /* fix mixer rate at 48khz. and its _must_ be 0x10000. */ freq = 0x10000; snd_es1968_apu_set_freq(chip, es->apu[2], freq); snd_es1968_apu_set_freq(chip, es->apu[3], freq); spin_lock_irqsave(&chip->reg_lock, flags); /* clear WP interrupts */ outw(1, chip->io_port + 0x04); /* enable WP ints */ outw(inw(chip->io_port + ESM_PORT_HOST_IRQ) | ESM_HIRQ_DSIE, chip->io_port + ESM_PORT_HOST_IRQ); spin_unlock_irqrestore(&chip->reg_lock, flags);}/******************* * ALSA Interface * *******************/static int snd_es1968_pcm_prepare(struct snd_pcm_substream *substream){ struct es1968 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct esschan *es = runtime->private_data; es->dma_size = snd_pcm_lib_buffer_bytes(substream); es->frag_size = snd_pcm_lib_period_bytes(substream); es->wav_shift = 1; /* maestro handles always 16bit */ es->fmt = 0; if (snd_pcm_format_width(runtime->format) == 16) es->fmt |= ESS_FMT_16BIT; if (runtime->channels > 1) { es->fmt |= ESS_FMT_STEREO; if (es->fmt & ESS_FMT_16BIT) /* 8bit is already word shifted */ es->wav_shift++; } es->bob_freq = snd_es1968_calc_bob_rate(chip, es, runtime); switch (es->mode) { case ESM_MODE_PLAY: snd_es1968_playback_setup(chip, es, runtime); break; case ESM_MODE_CAPTURE: snd_es1968_capture_setup(chip, es, runtime); break; } return 0;}static int snd_es1968_pcm_trigger(struct snd_pcm_substream *substream, int cmd){ struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es = substream->runtime->private_data; spin_lock(&chip->substream_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: if (es->running) break; snd_es1968_bob_inc(chip, es->bob_freq); es->count = 0; es->hwptr = 0; snd_es1968_pcm_start(chip, es); es->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: if (! es->running) break; snd_es1968_pcm_stop(chip, es); es->running = 0; snd_es1968_bob_dec(chip); break; } spin_unlock(&chip->substream_lock); return 0;}static snd_pcm_uframes_t snd_es1968_pcm_pointer(struct snd_pcm_substream *substream){ struct es1968 *chip = snd_pcm_substream_chip(substream); struct esschan *es = substream->runtime->private_data; unsigned int ptr; ptr = snd_es1968_get_dma_ptr(chip, es) << es->wav_shift; return bytes_to_frames(substream->runtime, ptr % es->dma_size);}static struct snd_pcm_hardware snd_es1968_playback = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, .period_bytes_min = 256, .period_bytes_max = 65536, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static struct snd_pcm_hardware snd_es1968_capture = { .info = (SNDRV_PCM_INFO_NONINTERLEAVED | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER | /*SNDRV_PCM_INFO_PAUSE |*/ SNDRV_PCM_INFO_RESUME), .formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 65536, .period_bytes_min = 256, .period_bytes_max = 65536, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};/* ************************* * DMA memory management * *************************//* Because the Maestro can only take addresses relative to the PCM base address register :( */static int calc_available_memory_size(struct es1968 *chip){ int max_size = 0; struct esm_memory *buf; mutex_lock(&chip->memory_mutex); list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes > max_size) max_size = buf->buf.bytes; } mutex_unlock(&chip->memory_mutex); if (max_size >= 128*1024) max_size = 127*1024; return max_size;}/* allocate a new memory chunk with the specified size */static struct esm_memory *snd_es1968_new_memory(struct es1968 *chip, int size){ struct esm_memory *buf; size = ALIGN(size, ESM_MEM_ALIGN); mutex_lock(&chip->memory_mutex); list_for_each_entry(buf, &chip->buf_list, list) { if (buf->empty && buf->buf.bytes >= size) goto __found; } mutex_unlock(&chip->memory_mutex); return NULL;__found: if (buf->buf.bytes > size) { struct esm_memory *chunk = kmalloc(sizeof(*chunk), GFP_KERNEL); if (chunk == NULL) { mutex_unlock(&chip->memory_mutex); return NULL; } chunk->buf = buf->buf; chunk->buf.bytes -= size; chunk->buf.area += size; chunk->buf.addr += size; chunk->empty = 1; buf->buf.bytes = size; list_add(&chunk->list, &buf->list); } buf->empty = 0; mutex_unlock(&chip->memory_mutex); return buf;}/* free a memory chunk */static void snd_es1968_free_memory(struct es1968 *chip, struct esm_memory *buf){ struct esm_memory *chunk; mutex_lock(&chip->memory_mutex); buf->empty = 1; if (buf->list.prev != &chip->buf_list) { chunk = list_entry(buf->list.prev, struct esm_memory, list); if (chunk->empty) { chunk->buf.bytes += buf->buf.bytes; list_del(&buf->list); kfree(buf); buf = chunk; } } if (buf->list.next != &chip->buf_list) { chunk = list_entry(buf->list.next, struct esm_memory, list); if (chunk->empty) { buf->buf.bytes += chunk->buf.bytes; list_del(&chunk->list);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -