📄 cs46xx_lib.c
字号:
if (runtime->periods == CS46XX_FRAGS) { if (runtime->dma_area != chip->capt.hw_area) snd_pcm_lib_free_pages(substream); runtime->dma_area = chip->capt.hw_area; runtime->dma_addr = chip->capt.hw_addr; runtime->dma_bytes = chip->capt.hw_size; substream->ops = &snd_cs46xx_capture_ops; } else { if (runtime->dma_area == chip->capt.hw_area) { runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; } if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) return err; substream->ops = &snd_cs46xx_capture_indirect_ops; } return 0;}static int snd_cs46xx_capture_hw_free(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->dma_area != chip->capt.hw_area) snd_pcm_lib_free_pages(substream); runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; return 0;}static int snd_cs46xx_capture_prepare(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_addr); chip->capt.shift = 2; chip->capt.sw_bufsize = snd_pcm_lib_buffer_bytes(substream); chip->capt.sw_data = chip->capt.sw_io = chip->capt.sw_ready = 0; chip->capt.hw_data = chip->capt.hw_io = chip->capt.hw_ready = 0; chip->capt.appl_ptr = 0; snd_cs46xx_set_capture_sample_rate(chip, runtime->rate); return 0;}static void snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){ cs46xx_t *chip = snd_magic_cast(cs46xx_t, dev_id, return); unsigned int status; /* * Read the Interrupt Status Register to clear the interrupt */ status = snd_cs46xx_peekBA0(chip, BA0_HISR); if ((status & 0x7fffffff) == 0) { snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV); return; } if ((status & HISR_VC0) && chip->pcm) { if (chip->play.substream) snd_pcm_period_elapsed(chip->play.substream); } if ((status & HISR_VC1) && chip->pcm) { if (chip->capt.substream) snd_pcm_period_elapsed(chip->capt.substream); } if ((status & HISR_MIDI) && chip->rmidi) { unsigned char c; spin_lock(&chip->reg_lock); while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_RBE) == 0) { c = snd_cs46xx_peekBA0(chip, BA0_MIDRP); if ((chip->midcr & MIDCR_RIE) == 0) continue; snd_rawmidi_receive(chip->midi_input, &c, 1); } while ((snd_cs46xx_peekBA0(chip, BA0_MIDSR) & MIDSR_TBF) == 0) { if ((chip->midcr & MIDCR_TIE) == 0) break; if (snd_rawmidi_transmit(chip->midi_output, &c, 1) != 1) { chip->midcr &= ~MIDCR_TIE; snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); break; } snd_cs46xx_pokeBA0(chip, BA0_MIDWP, c); } spin_unlock(&chip->reg_lock); } /* * EOI to the PCI part....reenables interrupts */ snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_CHGM | HICR_IEV);}static snd_pcm_hardware_t snd_cs46xx_playback ={ info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_RESUME), formats: (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE), rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, rate_min: 5500, rate_max: 48000, channels_min: 1, channels_max: 2, buffer_bytes_max: (256 * 1024), period_bytes_min: CS46XX_PERIOD_SIZE, period_bytes_max: CS46XX_PERIOD_SIZE, periods_min: CS46XX_FRAGS, periods_max: 1024, fifo_size: 0,};static snd_pcm_hardware_t snd_cs46xx_capture ={ info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_RESUME), formats: SNDRV_PCM_FMTBIT_S16_LE, rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, rate_min: 5500, rate_max: 48000, channels_min: 2, channels_max: 2, buffer_bytes_max: (256 * 1024), period_bytes_min: CS46XX_PERIOD_SIZE, period_bytes_max: CS46XX_PERIOD_SIZE, periods_min: CS46XX_FRAGS, periods_max: 1024, fifo_size: 0,};static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); if ((chip->play.hw_area = snd_malloc_pci_pages(chip->pci, chip->play.hw_size, &chip->play.hw_addr)) == NULL) return -ENOMEM; chip->play.substream = substream; substream->runtime->hw = snd_cs46xx_playback; if (chip->accept_valid) substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID; chip->active_ctrl(chip, 1); chip->amplifier_ctrl(chip, 1); return 0;}static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); if ((chip->capt.hw_area = snd_malloc_pci_pages(chip->pci, chip->capt.hw_size, &chip->capt.hw_addr)) == NULL) return -ENOMEM; chip->capt.substream = substream; substream->runtime->hw = snd_cs46xx_capture; if (chip->accept_valid) substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID; chip->active_ctrl(chip, 1); chip->amplifier_ctrl(chip, 1); return 0;}static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); chip->play.substream = NULL; snd_free_pci_pages(chip->pci, chip->play.hw_size, chip->play.hw_area, chip->play.hw_addr); chip->active_ctrl(chip, -1); chip->amplifier_ctrl(chip, -1); return 0;}static int snd_cs46xx_capture_close(snd_pcm_substream_t * substream){ cs46xx_t *chip = snd_pcm_substream_chip(substream); chip->capt.substream = NULL; snd_free_pci_pages(chip->pci, chip->capt.hw_size, chip->capt.hw_area, chip->capt.hw_addr); chip->active_ctrl(chip, -1); chip->amplifier_ctrl(chip, -1); return 0;}snd_pcm_ops_t snd_cs46xx_playback_ops = { open: snd_cs46xx_playback_open, close: snd_cs46xx_playback_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_cs46xx_playback_hw_params, hw_free: snd_cs46xx_playback_hw_free, prepare: snd_cs46xx_playback_prepare, trigger: snd_cs46xx_playback_trigger, pointer: snd_cs46xx_playback_direct_pointer,};snd_pcm_ops_t snd_cs46xx_playback_indirect_ops = { open: snd_cs46xx_playback_open, close: snd_cs46xx_playback_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_cs46xx_playback_hw_params, hw_free: snd_cs46xx_playback_hw_free, prepare: snd_cs46xx_playback_prepare, trigger: snd_cs46xx_playback_trigger, copy: snd_cs46xx_playback_copy, pointer: snd_cs46xx_playback_indirect_pointer,};snd_pcm_ops_t snd_cs46xx_capture_ops = { open: snd_cs46xx_capture_open, close: snd_cs46xx_capture_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_cs46xx_capture_hw_params, hw_free: snd_cs46xx_capture_hw_free, prepare: snd_cs46xx_capture_prepare, trigger: snd_cs46xx_capture_trigger, pointer: snd_cs46xx_capture_direct_pointer,};snd_pcm_ops_t snd_cs46xx_capture_indirect_ops = { open: snd_cs46xx_capture_open, close: snd_cs46xx_capture_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_cs46xx_capture_hw_params, hw_free: snd_cs46xx_capture_hw_free, prepare: snd_cs46xx_capture_prepare, trigger: snd_cs46xx_capture_trigger, copy: snd_cs46xx_capture_copy, pointer: snd_cs46xx_capture_indirect_pointer,};static void snd_cs46xx_pcm_free(snd_pcm_t *pcm){ cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return); chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}int __devinit snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t ** rpcm){ snd_pcm_t *pcm; int err; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(chip->card, "CS46xx", device, 1, 1, &pcm)) < 0) return err; pcm->private_data = chip; pcm->private_free = snd_cs46xx_pcm_free; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs46xx_capture_ops); /* global setup */ pcm->info_flags = 0; strcpy(pcm->name, "CS46xx"); chip->pcm = pcm; snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); if (rpcm) *rpcm = pcm; return 0;}/* * Mixer routines */static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97){ cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return); chip->ac97 = NULL; chip->eapd_switch = NULL;}static int snd_cs46xx_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 32767; return 0;}static int snd_cs46xx_vol_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; unsigned int val = snd_cs46xx_peek(chip, reg); ucontrol->value.integer.value[0] = 0xffff - (val >> 16); ucontrol->value.integer.value[1] = 0xffff - (val & 0xffff); return 0;}static int snd_cs46xx_vol_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ cs46xx_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value; unsigned int val = ((0xffff - ucontrol->value.integer.value[0]) << 16 | (0xffff - ucontrol->value.integer.value[1])); unsigned int old = snd_cs46xx_peek(chip, reg); int change = (old != val); if (change) snd_cs46xx_poke(chip, reg, val); return change;}static snd_kcontrol_new_t snd_cs46xx_controls[] __devinitdata = {{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: "DAC Volume", info: snd_cs46xx_vol_info, get: snd_cs46xx_vol_get, put: snd_cs46xx_vol_put, private_value: BA1_PVOL,},{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: "ADC Volume", info: snd_cs46xx_vol_info, get: snd_cs46xx_vol_get, put: snd_cs46xx_vol_put, private_value: BA1_CVOL,}};int __devinit snd_cs46xx_mixer(cs46xx_t *chip){ snd_card_t *card = chip->card; ac97_t ac97; snd_ctl_elem_id_t id; int err; int idx; memset(&ac97, 0, sizeof(ac97)); ac97.write = snd_cs46xx_ac97_write; ac97.read = snd_cs46xx_ac97_read; ac97.private_data = chip; ac97.private_free = snd_cs46xx_mixer_free_ac97; snd_cs46xx_ac97_write(&ac97, AC97_MASTER, 0x8000); for (idx = 0; idx < 100; ++idx) { if (snd_cs46xx_ac97_read(&ac97, AC97_MASTER) == 0x8000) goto _ok; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ/100); } return -ENXIO; _ok: if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97)) < 0) return err; for (idx = 0; idx < sizeof(snd_cs46xx_controls) / sizeof(snd_cs46xx_controls[0]); idx++) { snd_kcontrol_t *kctl; kctl = snd_ctl_new1(&snd_cs46xx_controls[idx], chip); if ((err = snd_ctl_add(card, kctl)) < 0) return err; } /* get EAPD mixer switch (for voyetra hack) */ memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "External Amplifier Power Down"); chip->eapd_switch = snd_ctl_find_id(chip->card, &id); return 0;}/* * RawMIDI interface */static void snd_cs46xx_midi_reset(cs46xx_t *chip){ snd_cs46xx_pokeBA0(chip, BA0_MIDCR, MIDCR_MRST); udelay(100); snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr);}static int snd_cs46xx_midi_input_open(snd_rawmidi_substream_t * substream){ unsigned long flags; cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); chip->active_ctrl(chip, 1); spin_lock_irqsave(&chip->reg_lock, flags); chip->uartm |= CS46XX_MODE_INPUT; chip->midcr |= MIDCR_RXE; chip->midi_input = substream; if (!(chip->uartm & CS46XX_MODE_OUTPUT)) { snd_cs46xx_midi_reset(chip); } else { snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static int snd_cs46xx_midi_input_close(snd_rawmidi_substream_t * substream){ unsigned long flags; cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr &= ~(MIDCR_RXE | MIDCR_RIE); chip->midi_input = NULL; if (!(chip->uartm & CS46XX_MODE_OUTPUT)) { snd_cs46xx_midi_reset(chip); } else { snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } chip->uartm &= ~CS46XX_MODE_INPUT; spin_unlock_irqrestore(&chip->reg_lock, flags); chip->active_ctrl(chip, -1); return 0;}static int snd_cs46xx_midi_output_open(snd_rawmidi_substream_t * substream){ unsigned long flags; cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); chip->active_ctrl(chip, 1); spin_lock_irqsave(&chip->reg_lock, flags); chip->uartm |= CS46XX_MODE_OUTPUT; chip->midcr |= MIDCR_TXE; chip->midi_output = substream; if (!(chip->uartm & CS46XX_MODE_INPUT)) { snd_cs46xx_midi_reset(chip); } else { snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } spin_unlock_irqrestore(&chip->reg_lock, flags); return 0;}static int snd_cs46xx_midi_output_close(snd_rawmidi_substream_t * substream){ unsigned long flags; cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return -ENXIO); spin_lock_irqsave(&chip->reg_lock, flags); chip->midcr &= ~(MIDCR_TXE | MIDCR_TIE); chip->midi_output = NULL; if (!(chip->uartm & CS46XX_MODE_INPUT)) { snd_cs46xx_midi_reset(chip); } else { snd_cs46xx_pokeBA0(chip, BA0_MIDCR, chip->midcr); } chip->uartm &= ~CS46XX_MODE_OUTPUT; spin_unlock_irqrestore(&chip->reg_lock, flags); chip->active_ctrl(chip, -1); return 0;}static void snd_cs46xx_midi_input_trigger(snd_rawmidi_substream_t * substream, int up){ unsigned long flags; cs46xx_t *chip = snd_magic_cast(cs46xx_t, substream->rmidi->private_data, return); spin_lock_irqsave(&chip->reg_lock, flags); if (up) { if ((chip->midcr & MIDCR_RIE) == 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -