📄 emu10k1x.c
字号:
/* close callback */static int snd_emu10k1x_playback_close(snd_pcm_substream_t *substream){ return 0;}/* hw_params callback */static int snd_emu10k1x_pcm_hw_params(snd_pcm_substream_t *substream, snd_pcm_hw_params_t * hw_params){ snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; if (! epcm->voice) { epcm->voice = &epcm->emu->voices[substream->pcm->device]; epcm->voice->use = 1; epcm->voice->epcm = epcm; } return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}/* hw_free callback */static int snd_emu10k1x_pcm_hw_free(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm; if (runtime->private_data == NULL) return 0; epcm = runtime->private_data; if (epcm->voice) { epcm->voice->use = 0; epcm->voice->epcm = NULL; epcm->voice = NULL; } return snd_pcm_lib_free_pages(substream);}/* prepare callback */static int snd_emu10k1x_pcm_prepare(snd_pcm_substream_t *substream){ emu10k1x_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; int voice = epcm->voice->number; u32 *table_base = (u32 *)(emu->dma_buffer.area+1024*voice); u32 period_size_bytes = frames_to_bytes(runtime, runtime->period_size); int i; for(i=0; i < runtime->periods; i++) { *table_base++=runtime->dma_addr+(i*period_size_bytes); *table_base++=period_size_bytes<<16; } snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_ADDR, voice, emu->dma_buffer.addr+1024*voice); snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_SIZE, voice, (runtime->periods - 1) << 19); snd_emu10k1x_ptr_write(emu, PLAYBACK_LIST_PTR, voice, 0); snd_emu10k1x_ptr_write(emu, PLAYBACK_POINTER, voice, 0); snd_emu10k1x_ptr_write(emu, PLAYBACK_UNKNOWN1, voice, 0); snd_emu10k1x_ptr_write(emu, PLAYBACK_UNKNOWN2, voice, 0); snd_emu10k1x_ptr_write(emu, PLAYBACK_DMA_ADDR, voice, runtime->dma_addr); snd_emu10k1x_ptr_write(emu, PLAYBACK_PERIOD_SIZE, voice, frames_to_bytes(runtime, runtime->period_size)<<16); return 0;}/* trigger callback */static int snd_emu10k1x_pcm_trigger(snd_pcm_substream_t *substream, int cmd){ emu10k1x_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; int channel = epcm->voice->number; int result = 0;// snd_printk(KERN_INFO "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream)); switch (cmd) { case SNDRV_PCM_TRIGGER_START: if(runtime->periods == 2) snd_emu10k1x_intr_enable(emu, (INTE_CH_0_LOOP | INTE_CH_0_HALF_LOOP) << channel); else snd_emu10k1x_intr_enable(emu, INTE_CH_0_LOOP << channel); epcm->running = 1; snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0)|(TRIGGER_CHANNEL_0<<channel)); break; case SNDRV_PCM_TRIGGER_STOP: epcm->running = 0; snd_emu10k1x_intr_disable(emu, (INTE_CH_0_LOOP | INTE_CH_0_HALF_LOOP) << channel); snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0) & ~(TRIGGER_CHANNEL_0<<channel)); break; default: result = -EINVAL; break; } return result;}/* pointer callback */static snd_pcm_uframes_tsnd_emu10k1x_pcm_pointer(snd_pcm_substream_t *substream){ emu10k1x_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; int channel = epcm->voice->number; snd_pcm_uframes_t ptr = 0, ptr1 = 0, ptr2= 0,ptr3 = 0,ptr4 = 0; if (!epcm->running) return 0; ptr3 = snd_emu10k1x_ptr_read(emu, PLAYBACK_LIST_PTR, channel); ptr1 = snd_emu10k1x_ptr_read(emu, PLAYBACK_POINTER, channel); ptr4 = snd_emu10k1x_ptr_read(emu, PLAYBACK_LIST_PTR, channel); if(ptr4 == 0 && ptr1 == frames_to_bytes(runtime, runtime->buffer_size)) return 0; if (ptr3 != ptr4) ptr1 = snd_emu10k1x_ptr_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;}/* operators */static snd_pcm_ops_t snd_emu10k1x_playback_ops = { .open = snd_emu10k1x_playback_open, .close = snd_emu10k1x_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_emu10k1x_pcm_hw_params, .hw_free = snd_emu10k1x_pcm_hw_free, .prepare = snd_emu10k1x_pcm_prepare, .trigger = snd_emu10k1x_pcm_trigger, .pointer = snd_emu10k1x_pcm_pointer,};/* open_capture callback */static int snd_emu10k1x_pcm_open_capture(snd_pcm_substream_t *substream){ emu10k1x_t *chip = snd_pcm_substream_chip(substream); emu10k1x_pcm_t *epcm; snd_pcm_runtime_t *runtime = substream->runtime; int err; if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) return err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = chip; epcm->substream = substream; runtime->private_data = epcm; runtime->private_free = snd_emu10k1x_pcm_free_substream; runtime->hw = snd_emu10k1x_capture_hw; return 0;}/* close callback */static int snd_emu10k1x_pcm_close_capture(snd_pcm_substream_t *substream){ return 0;}/* hw_params callback */static int snd_emu10k1x_pcm_hw_params_capture(snd_pcm_substream_t *substream, snd_pcm_hw_params_t * hw_params){ snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; if (! epcm->voice) { if (epcm->emu->capture_voice.use) return -EBUSY; epcm->voice = &epcm->emu->capture_voice; epcm->voice->epcm = epcm; epcm->voice->use = 1; } return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}/* hw_free callback */static int snd_emu10k1x_pcm_hw_free_capture(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm; if (runtime->private_data == NULL) return 0; epcm = runtime->private_data; if (epcm->voice) { epcm->voice->use = 0; epcm->voice->epcm = NULL; epcm->voice = NULL; } return snd_pcm_lib_free_pages(substream);}/* prepare capture callback */static int snd_emu10k1x_pcm_prepare_capture(snd_pcm_substream_t *substream){ emu10k1x_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_emu10k1x_ptr_write(emu, CAPTURE_DMA_ADDR, 0, runtime->dma_addr); snd_emu10k1x_ptr_write(emu, CAPTURE_BUFFER_SIZE, 0, frames_to_bytes(runtime, runtime->buffer_size)<<16); // buffer size in bytes snd_emu10k1x_ptr_write(emu, CAPTURE_POINTER, 0, 0); snd_emu10k1x_ptr_write(emu, CAPTURE_UNKNOWN, 0, 0); return 0;}/* trigger_capture callback */static int snd_emu10k1x_pcm_trigger_capture(snd_pcm_substream_t *substream, int cmd){ emu10k1x_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; int result = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_emu10k1x_intr_enable(emu, INTE_CAP_0_LOOP | INTE_CAP_0_HALF_LOOP); snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0)|TRIGGER_CAPTURE); epcm->running = 1; break; case SNDRV_PCM_TRIGGER_STOP: epcm->running = 0; snd_emu10k1x_intr_disable(emu, INTE_CAP_0_LOOP | INTE_CAP_0_HALF_LOOP); snd_emu10k1x_ptr_write(emu, TRIGGER_CHANNEL, 0, snd_emu10k1x_ptr_read(emu, TRIGGER_CHANNEL, 0) & ~(TRIGGER_CAPTURE)); break; default: result = -EINVAL; break; } return result;}/* pointer_capture callback */static snd_pcm_uframes_tsnd_emu10k1x_pcm_pointer_capture(snd_pcm_substream_t *substream){ emu10k1x_t *emu = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; emu10k1x_pcm_t *epcm = runtime->private_data; snd_pcm_uframes_t ptr; if (!epcm->running) return 0; ptr = bytes_to_frames(runtime, snd_emu10k1x_ptr_read(emu, CAPTURE_POINTER, 0)); if (ptr >= runtime->buffer_size) ptr -= runtime->buffer_size; return ptr;}static snd_pcm_ops_t snd_emu10k1x_capture_ops = { .open = snd_emu10k1x_pcm_open_capture, .close = snd_emu10k1x_pcm_close_capture, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_emu10k1x_pcm_hw_params_capture, .hw_free = snd_emu10k1x_pcm_hw_free_capture, .prepare = snd_emu10k1x_pcm_prepare_capture, .trigger = snd_emu10k1x_pcm_trigger_capture, .pointer = snd_emu10k1x_pcm_pointer_capture,};static unsigned short snd_emu10k1x_ac97_read(ac97_t *ac97, unsigned short reg){ emu10k1x_t *emu = ac97->private_data; unsigned long flags; unsigned short val; spin_lock_irqsave(&emu->emu_lock, flags); outb(reg, emu->port + AC97ADDRESS); val = inw(emu->port + AC97DATA); spin_unlock_irqrestore(&emu->emu_lock, flags); return val;}static void snd_emu10k1x_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val){ emu10k1x_t *emu = ac97->private_data; unsigned long flags; spin_lock_irqsave(&emu->emu_lock, flags); outb(reg, emu->port + AC97ADDRESS); outw(val, emu->port + AC97DATA); spin_unlock_irqrestore(&emu->emu_lock, flags);}static int snd_emu10k1x_ac97(emu10k1x_t *chip){ ac97_bus_t *pbus; ac97_template_t ac97; int err; static ac97_bus_ops_t ops = { .write = snd_emu10k1x_ac97_write, .read = snd_emu10k1x_ac97_read, }; if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &pbus)) < 0) return err; pbus->no_vra = 1; /* we don't need VRA */ memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.scaps = AC97_SCAP_NO_SPDIF; return snd_ac97_mixer(pbus, &ac97, &chip->ac97);}static int snd_emu10k1x_free(emu10k1x_t *chip){ snd_emu10k1x_ptr_write(chip, TRIGGER_CHANNEL, 0, 0); // disable interrupts outl(0, chip->port + INTE); // disable audio outl(HCFG_LOCKSOUNDCACHE, chip->port + HCFG); // release the i/o port release_and_free_resource(chip->res_port); // release the irq if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); // release the DMA if (chip->dma_buffer.area) { snd_dma_free_pages(&chip->dma_buffer); } pci_disable_device(chip->pci); // release the data kfree(chip); return 0;}static int snd_emu10k1x_dev_free(snd_device_t *device){ emu10k1x_t *chip = device->device_data; return snd_emu10k1x_free(chip);}static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id, struct pt_regs *regs){ unsigned int status; emu10k1x_t *chip = dev_id; emu10k1x_voice_t *pvoice = chip->voices; int i; int mask; status = inl(chip->port + IPR); if(status) { // capture interrupt if(status & (IPR_CAP_0_LOOP | IPR_CAP_0_HALF_LOOP)) { emu10k1x_voice_t *pvoice = &chip->capture_voice; if(pvoice->use) snd_emu10k1x_pcm_interrupt(chip, pvoice); else snd_emu10k1x_intr_disable(chip, INTE_CAP_0_LOOP | INTE_CAP_0_HALF_LOOP); } mask = IPR_CH_0_LOOP|IPR_CH_0_HALF_LOOP; for(i = 0; i < 3; i++) { if(status & mask) { if(pvoice->use) snd_emu10k1x_pcm_interrupt(chip, pvoice); else snd_emu10k1x_intr_disable(chip, mask); } pvoice++; mask <<= 1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -