📄 bt87x.c
字号:
{ struct snd_bt87x *chip = dev_id; unsigned int status, irq_status; status = snd_bt87x_readl(chip, REG_INT_STAT); irq_status = status & chip->interrupt_mask; if (!irq_status) return IRQ_NONE; snd_bt87x_writel(chip, REG_INT_STAT, irq_status); if (irq_status & ERROR_INTERRUPTS) { if (irq_status & (INT_FBUS | INT_FTRGT)) snd_printk(KERN_WARNING "FIFO overrun, status %#08x\n", status); if (irq_status & INT_OCERR) snd_printk(KERN_ERR "internal RISC error, status %#08x\n", status); if (irq_status & (INT_PPERR | INT_RIPERR | INT_PABORT)) snd_bt87x_pci_error(chip, irq_status); } if ((irq_status & INT_RISCI) && (chip->reg_control & CTL_ACAP_EN)) { int current_block, irq_block; /* assume that exactly one line has been recorded */ chip->current_line = (chip->current_line + 1) % chip->lines; /* but check if some interrupts have been skipped */ current_block = chip->current_line * 16 / chip->lines; irq_block = status >> INT_RISCS_SHIFT; if (current_block != irq_block) chip->current_line = (irq_block * chip->lines + 15) / 16; snd_pcm_period_elapsed(chip->substream); } return IRQ_HANDLED;}static struct snd_pcm_hardware snd_bt87x_digital_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = 0, /* set at runtime */ .channels_min = 2, .channels_max = 2, .buffer_bytes_max = 255 * 4092, .period_bytes_min = 32, .period_bytes_max = 4092, .periods_min = 2, .periods_max = 255,};static struct snd_pcm_hardware snd_bt87x_analog_hw = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, .rates = SNDRV_PCM_RATE_KNOT, .rate_min = ANALOG_CLOCK / CLOCK_DIV_MAX, .rate_max = ANALOG_CLOCK / CLOCK_DIV_MIN, .channels_min = 1, .channels_max = 1, .buffer_bytes_max = 255 * 4092, .period_bytes_min = 32, .period_bytes_max = 4092, .periods_min = 2, .periods_max = 255,};static int snd_bt87x_set_digital_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime){ chip->reg_control |= CTL_DA_IOM_DA | CTL_A_PWRDN; runtime->hw = snd_bt87x_digital_hw; runtime->hw.rates = snd_pcm_rate_to_rate_bit(chip->board.dig_rate); runtime->hw.rate_min = chip->board.dig_rate; runtime->hw.rate_max = chip->board.dig_rate; return 0;}static int snd_bt87x_set_analog_hw(struct snd_bt87x *chip, struct snd_pcm_runtime *runtime){ static struct snd_ratnum analog_clock = { .num = ANALOG_CLOCK, .den_min = CLOCK_DIV_MIN, .den_max = CLOCK_DIV_MAX, .den_step = 1 }; static struct snd_pcm_hw_constraint_ratnums constraint_rates = { .nrats = 1, .rats = &analog_clock }; chip->reg_control &= ~(CTL_DA_IOM_DA | CTL_A_PWRDN); runtime->hw = snd_bt87x_analog_hw; return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraint_rates);}static int snd_bt87x_pcm_open(struct snd_pcm_substream *substream){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; if (test_and_set_bit(0, &chip->opened)) return -EBUSY; if (substream->pcm->device == DEVICE_DIGITAL) err = snd_bt87x_set_digital_hw(chip, runtime); else err = snd_bt87x_set_analog_hw(chip, runtime); if (err < 0) goto _error; err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; chip->substream = substream; return 0;_error: clear_bit(0, &chip->opened); smp_mb__after_clear_bit(); return err;}static int snd_bt87x_close(struct snd_pcm_substream *substream){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); spin_lock_irq(&chip->reg_lock); chip->reg_control |= CTL_A_PWRDN; snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); spin_unlock_irq(&chip->reg_lock); chip->substream = NULL; clear_bit(0, &chip->opened); smp_mb__after_clear_bit(); return 0;}static int snd_bt87x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); int err; err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; return snd_bt87x_create_risc(chip, substream, params_periods(hw_params), params_period_bytes(hw_params));}static int snd_bt87x_hw_free(struct snd_pcm_substream *substream){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); snd_bt87x_free_risc(chip); snd_pcm_lib_free_pages(substream); return 0;}static int snd_bt87x_prepare(struct snd_pcm_substream *substream){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int decimation; spin_lock_irq(&chip->reg_lock); chip->reg_control &= ~(CTL_DA_SDR_MASK | CTL_DA_SBR); decimation = (ANALOG_CLOCK + runtime->rate / 4) / runtime->rate; chip->reg_control |= decimation << CTL_DA_SDR_SHIFT; if (runtime->format == SNDRV_PCM_FORMAT_S8) chip->reg_control |= CTL_DA_SBR; snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); spin_unlock_irq(&chip->reg_lock); return 0;}static int snd_bt87x_start(struct snd_bt87x *chip){ spin_lock(&chip->reg_lock); chip->current_line = 0; chip->reg_control |= CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN; snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr); snd_bt87x_writel(chip, REG_PACKET_LEN, chip->line_bytes | (chip->lines << 16)); snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); spin_unlock(&chip->reg_lock); return 0;}static int snd_bt87x_stop(struct snd_bt87x *chip){ spin_lock(&chip->reg_lock); chip->reg_control &= ~(CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); snd_bt87x_writel(chip, REG_INT_MASK, 0); snd_bt87x_writel(chip, REG_INT_STAT, MY_INTERRUPTS); spin_unlock(&chip->reg_lock); return 0;}static int snd_bt87x_trigger(struct snd_pcm_substream *substream, int cmd){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_START: return snd_bt87x_start(chip); case SNDRV_PCM_TRIGGER_STOP: return snd_bt87x_stop(chip); default: return -EINVAL; }}static snd_pcm_uframes_t snd_bt87x_pointer(struct snd_pcm_substream *substream){ struct snd_bt87x *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);}static struct snd_pcm_ops snd_bt87x_pcm_ops = { .open = snd_bt87x_pcm_open, .close = snd_bt87x_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_bt87x_hw_params, .hw_free = snd_bt87x_hw_free, .prepare = snd_bt87x_prepare, .trigger = snd_bt87x_trigger, .pointer = snd_bt87x_pointer, .page = snd_pcm_sgbuf_ops_page,};static int snd_bt87x_capture_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info){ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; info->count = 1; info->value.integer.min = 0; info->value.integer.max = 15; return 0;}static int snd_bt87x_capture_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); value->value.integer.value[0] = (chip->reg_control & CTL_A_GAIN_MASK) >> CTL_A_GAIN_SHIFT; return 0;}static int snd_bt87x_capture_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); u32 old_control; int changed; spin_lock_irq(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_GAIN_MASK) | (value->value.integer.value[0] << CTL_A_GAIN_SHIFT); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = old_control != chip->reg_control; spin_unlock_irq(&chip->reg_lock); return changed;}static struct snd_kcontrol_new snd_bt87x_capture_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Volume", .info = snd_bt87x_capture_volume_info, .get = snd_bt87x_capture_volume_get, .put = snd_bt87x_capture_volume_put,};#define snd_bt87x_capture_boost_info snd_ctl_boolean_mono_infostatic int snd_bt87x_capture_boost_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); value->value.integer.value[0] = !! (chip->reg_control & CTL_A_G2X); return 0;}static int snd_bt87x_capture_boost_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol); u32 old_control; int changed; spin_lock_irq(&chip->reg_lock); old_control = chip->reg_control; chip->reg_control = (chip->reg_control & ~CTL_A_G2X) | (value->value.integer.value[0] ? CTL_A_G2X : 0); snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control); changed = chip->reg_control != old_control; spin_unlock_irq(&chip->reg_lock); return changed;}static struct snd_kcontrol_new snd_bt87x_capture_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Boost", .info = snd_bt87x_capture_boost_info, .get = snd_bt87x_capture_boost_get, .put = snd_bt87x_capture_boost_put,};static int snd_bt87x_capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info){ static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"}; info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; info->value.enumerated.items = 3; if (info->value.enumerated.item > 2) info->value.enumerated.item = 2; strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]); return 0;}static int snd_bt87x_capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value){ struct snd_bt87x *chip = snd_kcontrol_chip(kcontrol);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -