📄 p16v.c
字号:
u32 inte = 0; int running=0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: running=1; break; case SNDRV_PCM_TRIGGER_STOP: default: running=0; break; } snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); runtime = s->runtime; epcm = runtime->private_data; channel = substream->pcm->device-emu->p16v_device_offset; //snd_printk("p16v channel=%d\n",channel); epcm->running = running; basic |= (0x1<<channel); inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel); snd_pcm_trigger_done(s, substream); } //snd_printk("basic=0x%x, inte=0x%x\n",basic, inte); switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_p16v_intr_enable(emu, inte); snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)| (basic)); break; case SNDRV_PCM_TRIGGER_STOP: snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(basic)); snd_p16v_intr_disable(emu, inte); break; default: result = -EINVAL; break; } return result;}/* trigger_capture callback */static int snd_p16v_pcm_trigger_capture(struct snd_pcm_substream *substream, int cmd){ struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; int channel = 0; int result = 0; u32 inte = INTE2_CAPTURE_CH_0_LOOP | INTE2_CAPTURE_CH_0_HALF_LOOP; switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_p16v_intr_enable(emu, inte); snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0)|(0x100<<channel)); epcm->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & ~(0x100<<channel)); snd_p16v_intr_disable(emu, inte); //snd_emu10k1_ptr20_write(emu, EXTENDED_INT_MASK, 0, snd_emu10k1_ptr20_read(emu, EXTENDED_INT_MASK, 0) & ~(0x110000<<channel)); epcm->running = 0; break; default: result = -EINVAL; break; } return result;}/* pointer_playback callback */static snd_pcm_uframes_tsnd_p16v_pcm_pointer_playback(struct snd_pcm_substream *substream){ struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; int channel = substream->pcm->device - emu->p16v_device_offset; if (!epcm->running) return 0; ptr3 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel); ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel); ptr4 = snd_emu10k1_ptr20_read(emu, PLAYBACK_LIST_PTR, channel); if (ptr3 != ptr4) ptr1 = snd_emu10k1_ptr20_read(emu, PLAYBACK_POINTER, channel); ptr2 = bytes_to_frames(runtime, ptr1); ptr2+= (ptr4 >> 3) * runtime->period_size; ptr=ptr2; if (ptr >= runtime->buffer_size) ptr -= runtime->buffer_size; return ptr;}/* pointer_capture callback */static snd_pcm_uframes_tsnd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream){ struct snd_emu10k1 *emu = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_emu10k1_pcm *epcm = runtime->private_data; snd_pcm_uframes_t ptr, ptr1, ptr2 = 0; int channel = 0; if (!epcm->running) return 0; ptr1 = snd_emu10k1_ptr20_read(emu, CAPTURE_POINTER, channel); ptr2 = bytes_to_frames(runtime, ptr1); ptr=ptr2; if (ptr >= runtime->buffer_size) { ptr -= runtime->buffer_size; printk(KERN_WARNING "buffer capture limited!\n"); } //printk("ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, (int)runtime->rate); return ptr;}/* operators */static struct snd_pcm_ops snd_p16v_playback_front_ops = { .open = snd_p16v_pcm_open_playback_front, .close = snd_p16v_pcm_close_playback, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_p16v_pcm_hw_params_playback, .hw_free = snd_p16v_pcm_hw_free_playback, .prepare = snd_p16v_pcm_prepare_playback, .trigger = snd_p16v_pcm_trigger_playback, .pointer = snd_p16v_pcm_pointer_playback,};static struct snd_pcm_ops snd_p16v_capture_ops = { .open = snd_p16v_pcm_open_capture, .close = snd_p16v_pcm_close_capture, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_p16v_pcm_hw_params_capture, .hw_free = snd_p16v_pcm_hw_free_capture, .prepare = snd_p16v_pcm_prepare_capture, .trigger = snd_p16v_pcm_trigger_capture, .pointer = snd_p16v_pcm_pointer_capture,};int snd_p16v_free(struct snd_emu10k1 *chip){ // release the data if (chip->p16v_buffer.area) { snd_dma_free_pages(&chip->p16v_buffer); //snd_printk("period lables free: %p\n", &chip->p16v_buffer); } return 0;}int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm){ struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; int capture=1; //snd_printk("snd_p16v_pcm called. device=%d\n", device); emu->p16v_device_offset = device; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(emu->card, "p16v", device, 1, capture, &pcm)) < 0) return err; pcm->private_data = emu; // Single playback 8 channel device. // Single capture 2 channel device. snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_p16v_playback_front_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_p16v_capture_ops); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; strcpy(pcm->name, "p16v"); emu->pcm_p16v = pcm; for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) { if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) return err; //snd_printk("preallocate playback substream: err=%d\n", err); } for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) { if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 65536 - 64, 65536 - 64)) < 0) return err; //snd_printk("preallocate capture substream: err=%d\n", err); } if (rpcm) *rpcm = pcm; return 0;}static int snd_p16v_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 255; return 0;}static int snd_p16v_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int high_low = (kcontrol->private_value >> 8) & 0xff; int reg = kcontrol->private_value & 0xff; u32 value; value = snd_emu10k1_ptr20_read(emu, reg, high_low); if (high_low) { ucontrol->value.integer.value[0] = 0xff - ((value >> 24) & 0xff); /* Left */ ucontrol->value.integer.value[1] = 0xff - ((value >> 16) & 0xff); /* Right */ } else { ucontrol->value.integer.value[0] = 0xff - ((value >> 8) & 0xff); /* Left */ ucontrol->value.integer.value[1] = 0xff - ((value >> 0) & 0xff); /* Right */ } return 0;}static int snd_p16v_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); int high_low = (kcontrol->private_value >> 8) & 0xff; int reg = kcontrol->private_value & 0xff; u32 value, oval; oval = value = snd_emu10k1_ptr20_read(emu, reg, 0); if (high_low == 1) { value &= 0xffff; value |= ((0xff - ucontrol->value.integer.value[0]) << 24) | ((0xff - ucontrol->value.integer.value[1]) << 16); } else { value &= 0xffff0000; value |= ((0xff - ucontrol->value.integer.value[0]) << 8) | ((0xff - ucontrol->value.integer.value[1]) ); } if (value != oval) { snd_emu10k1_ptr20_write(emu, reg, 0, value); return 1; } return 0;}static int snd_p16v_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[8] = { "SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S", "CDIF", "FX", "AC97" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 8; if (uinfo->value.enumerated.item > 7) uinfo->value.enumerated.item = 7; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_p16v_capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = emu->p16v_capture_source; return 0;}static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; u32 mask; u32 source; val = ucontrol->value.enumerated.item[0] ; change = (emu->p16v_capture_source != val); if (change) { emu->p16v_capture_source = val; source = (val << 28) | (val << 24) | (val << 20) | (val << 16); mask = snd_emu10k1_ptr20_read(emu, BASIC_INTERRUPT, 0) & 0xffff; snd_emu10k1_ptr20_write(emu, BASIC_INTERRUPT, 0, source | mask); } return change;}static int snd_p16v_capture_channel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[4] = { "0", "1", "2", "3", }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_p16v_capture_channel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = emu->p16v_capture_channel; return 0;}static int snd_p16v_capture_channel_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; u32 tmp; val = ucontrol->value.enumerated.item[0] ; change = (emu->p16v_capture_channel != val); if (change) { emu->p16v_capture_channel = val; tmp = snd_emu10k1_ptr20_read(emu, CAPTURE_P16V_SOURCE, 0) & 0xfffc; snd_emu10k1_ptr20_write(emu, CAPTURE_P16V_SOURCE, 0, tmp | val); } return change;}#define P16V_VOL(xname,xreg,xhl) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_p16v_volume_info, \ .get = snd_p16v_volume_get, \ .put = snd_p16v_volume_put, \ .private_value = ((xreg) | ((xhl) << 8)) \}static struct snd_kcontrol_new p16v_mixer_controls[] __devinitdata = { P16V_VOL("HD Analog Front Playback Volume", PLAYBACK_VOLUME_MIXER9, 0), P16V_VOL("HD Analog Rear Playback Volume", PLAYBACK_VOLUME_MIXER10, 1), P16V_VOL("HD Analog Center/LFE Playback Volume", PLAYBACK_VOLUME_MIXER9, 1), P16V_VOL("HD Analog Side Playback Volume", PLAYBACK_VOLUME_MIXER10, 0), P16V_VOL("HD SPDIF Front Playback Volume", PLAYBACK_VOLUME_MIXER7, 0), P16V_VOL("HD SPDIF Rear Playback Volume", PLAYBACK_VOLUME_MIXER8, 1), P16V_VOL("HD SPDIF Center/LFE Playback Volume", PLAYBACK_VOLUME_MIXER7, 1), P16V_VOL("HD SPDIF Side Playback Volume", PLAYBACK_VOLUME_MIXER8, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "HD source Capture", .info = snd_p16v_capture_source_info, .get = snd_p16v_capture_source_get, .put = snd_p16v_capture_source_put }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "HD channel Capture", .info = snd_p16v_capture_channel_info, .get = snd_p16v_capture_channel_get, .put = snd_p16v_capture_channel_put },};int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu){ int i, err; struct snd_card *card = emu->card; for (i = 0; i < ARRAY_SIZE(p16v_mixer_controls); i++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&p16v_mixer_controls[i], emu))) < 0) return err; } return 0;}#ifdef CONFIG_PM#define NUM_CHS 1 /* up to 4, but only first channel is used */int __devinit snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu){ emu->p16v_saved = vmalloc(NUM_CHS * 4 * 0x80); if (! emu->p16v_saved) return -ENOMEM; return 0;}void snd_p16v_free_pm_buffer(struct snd_emu10k1 *emu){ vfree(emu->p16v_saved);}void snd_p16v_suspend(struct snd_emu10k1 *emu){ int i, ch; unsigned int *val; val = emu->p16v_saved; for (ch = 0; ch < NUM_CHS; ch++) for (i = 0; i < 0x80; i++, val++) *val = snd_emu10k1_ptr20_read(emu, i, ch);}void snd_p16v_resume(struct snd_emu10k1 *emu){ int i, ch; unsigned int *val; val = emu->p16v_saved; for (ch = 0; ch < NUM_CHS; ch++) for (i = 0; i < 0x80; i++, val++) snd_emu10k1_ptr20_write(emu, i, ch, *val);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -