es1938.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,732 行 · 第 1/4 页
C
1,732 行
/* ---------------------------------------------------------------------- * Audio1 Capture (ADC) * ----------------------------------------------------------------------*/static snd_pcm_hardware_t snd_es1938_capture ={ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 6000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */ .period_bytes_min = 64, .period_bytes_max = 0x8000, .periods_min = 1, .periods_max = 1024, .fifo_size = 256,};/* ----------------------------------------------------------------------- * Audio2 Playback (DAC) * -----------------------------------------------------------------------*/static snd_pcm_hardware_t snd_es1938_playback ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 6000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 0x8000, /* DMA controller screws on higher values */ .period_bytes_min = 64, .period_bytes_max = 0x8000, .periods_min = 1, .periods_max = 1024, .fifo_size = 256,};static int snd_es1938_capture_open(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; if (chip->playback2_substream) return -EAGAIN; chip->capture_substream = substream; runtime->hw = snd_es1938_capture; snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_clocks); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00); return 0;}static int snd_es1938_playback_open(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; switch (substream->number) { case 0: chip->playback1_substream = substream; break; case 1: if (chip->capture_substream) return -EAGAIN; chip->playback2_substream = substream; break; default: snd_BUG(); return -EINVAL; } runtime->hw = snd_es1938_playback; snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_clocks); snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, 0xff00); return 0;}static int snd_es1938_capture_close(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); chip->capture_substream = NULL; return 0;}static int snd_es1938_playback_close(snd_pcm_substream_t * substream){ es1938_t *chip = snd_pcm_substream_chip(substream); switch (substream->number) { case 0: chip->playback1_substream = NULL; break; case 1: chip->playback2_substream = NULL; break; default: snd_BUG(); return -EINVAL; } return 0;}static snd_pcm_ops_t snd_es1938_playback_ops = { .open = snd_es1938_playback_open, .close = snd_es1938_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_es1938_pcm_hw_params, .hw_free = snd_es1938_pcm_hw_free, .prepare = snd_es1938_playback_prepare, .trigger = snd_es1938_playback_trigger, .pointer = snd_es1938_playback_pointer,};static snd_pcm_ops_t snd_es1938_capture_ops = { .open = snd_es1938_capture_open, .close = snd_es1938_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_es1938_pcm_hw_params, .hw_free = snd_es1938_pcm_hw_free, .prepare = snd_es1938_capture_prepare, .trigger = snd_es1938_capture_trigger, .pointer = snd_es1938_capture_pointer, .copy = snd_es1938_capture_copy,};static void snd_es1938_free_pcm(snd_pcm_t *pcm){ snd_pcm_lib_preallocate_free_for_all(pcm);}static int __devinit snd_es1938_new_pcm(es1938_t *chip, int device){ snd_pcm_t *pcm; int err; if ((err = snd_pcm_new(chip->card, "es-1938-1946", device, 2, 1, &pcm)) < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_es1938_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_es1938_capture_ops); pcm->private_data = chip; pcm->private_free = snd_es1938_free_pcm; pcm->info_flags = 0; strcpy(pcm->name, "ESS Solo-1"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 64*1024); chip->pcm = pcm; return 0;}/* ------------------------------------------------------------------- * * *** Mixer part *** */static int snd_es1938_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ static char *texts[8] = { "Mic", "Mic Master", "CD", "AOUT", "Mic1", "Mix", "Line", "Master" }; 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_es1938_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.enumerated.item[0] = snd_es1938_mixer_read(chip, 0x1c) & 0x07; return 0;}static int snd_es1938_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); unsigned char val = ucontrol->value.enumerated.item[0]; if (val > 7) return -EINVAL; return snd_es1938_mixer_bits(chip, 0x1c, 0x07, val) != val;}static int snd_es1938_info_spatializer_enable(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int snd_es1938_get_spatializer_enable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); unsigned char val = snd_es1938_mixer_read(chip, 0x50); ucontrol->value.integer.value[0] = !!(val & 8); return 0;}static int snd_es1938_put_spatializer_enable(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); unsigned char oval, nval; int change; nval = ucontrol->value.integer.value[0] ? 0x0c : 0x04; oval = snd_es1938_mixer_read(chip, 0x50) & 0x0c; change = nval != oval; if (change) { snd_es1938_mixer_write(chip, 0x50, nval & ~0x04); snd_es1938_mixer_write(chip, 0x50, nval); } return change;}static int snd_es1938_info_hw_volume(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 = 63; return 0;}static int snd_es1938_get_hw_volume(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = snd_es1938_mixer_read(chip, 0x61) & 0x3f; ucontrol->value.integer.value[1] = snd_es1938_mixer_read(chip, 0x63) & 0x3f; return 0;}static int snd_es1938_info_hw_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int snd_es1938_get_hw_switch(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = !(snd_es1938_mixer_read(chip, 0x61) & 0x40); ucontrol->value.integer.value[1] = !(snd_es1938_mixer_read(chip, 0x63) & 0x40); return 0;}static void snd_es1938_hwv_free(snd_kcontrol_t *kcontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); chip->master_volume = NULL; chip->master_switch = NULL; chip->hw_volume = NULL; chip->hw_switch = NULL;}static int snd_es1938_reg_bits(es1938_t *chip, unsigned char reg, unsigned char mask, unsigned char val){ if (reg < 0xa0) return snd_es1938_mixer_bits(chip, reg, mask, val); else return snd_es1938_bits(chip, reg, mask, val);}static int snd_es1938_reg_read(es1938_t *chip, unsigned char reg){ if (reg < 0xa0) return snd_es1938_mixer_read(chip, reg); else return snd_es1938_read(chip, reg);}#define ES1938_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_es1938_info_single, \ .get = snd_es1938_get_single, .put = snd_es1938_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_es1938_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask = (kcontrol->private_value >> 16) & 0xff; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_es1938_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; int val; val = snd_es1938_reg_read(chip, reg); ucontrol->value.integer.value[0] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0;}static int snd_es1938_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); int reg = kcontrol->private_value & 0xff; int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; unsigned char val; val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; mask <<= shift; val <<= shift; return snd_es1938_reg_bits(chip, reg, mask, val) != val;}#define ES1938_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_es1938_info_double, \ .get = snd_es1938_get_double, .put = snd_es1938_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }static int snd_es1938_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ int mask = (kcontrol->private_value >> 24) & 0xff; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = mask; return 0;}static int snd_es1938_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; int shift_right = (kcontrol->private_value >> 19) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; unsigned char left, right; left = snd_es1938_reg_read(chip, left_reg); if (left_reg != right_reg) right = snd_es1938_reg_read(chip, right_reg); else right = left; ucontrol->value.integer.value[0] = (left >> shift_left) & mask; ucontrol->value.integer.value[1] = (right >> shift_right) & mask; if (invert) { ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; } return 0;}static int snd_es1938_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ es1938_t *chip = snd_kcontrol_chip(kcontrol); int left_reg = kcontrol->private_value & 0xff; int right_reg = (kcontrol->private_value >> 8) & 0xff; int shift_left = (kcontrol->private_value >> 16) & 0x07; int shift_right = (kcontrol->private_value >> 19) & 0x07; int mask = (kcontrol->private_value >> 24) & 0xff; int invert = (kcontrol->private_value >> 22) & 1; int change; unsigned char val1, val2, mask1, mask2; val1 = ucontrol->value.integer.value[0] & mask; val2 = ucontrol->value.integer.value[1] & mask; if (invert) { val1 = mask - val1; val2 = mask - val2; } val1 <<= shift_left; val2 <<= shift_right; mask1 = mask << shift_left; mask2 = mask << shift_right; if (left_reg != right_reg) { change = 0; if (snd_es1938_reg_bits(chip, left_reg, mask1, val1) != val1) change = 1; if (snd_es1938_reg_bits(chip, right_reg, mask2, val2) != val2) change = 1; } else { change = (snd_es1938_reg_bits(chip, left_reg, mask1 | mask2, val1 | val2) != (val1 | val2)); } return change;}static snd_kcontrol_new_t snd_es1938_controls[] = {ES1938_DOUBLE("Master Playback Volume", 0, 0x60, 0x62, 0, 0, 63, 0),ES1938_DOUBLE("Master Playback Switch", 0, 0x60, 0x62, 6, 6, 1, 1),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Hardware Master Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READ, .info = snd_es1938_info_hw_volume, .get = snd_es1938_get_hw_volume,},{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Hardware Master Playback Switch", .access = SNDRV_CTL_ELEM_ACCESS_READ, .info = snd_es1938_info_hw_switch, .get = snd_es1938_get_hw_switch,},
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?