📄 sonicvibes.c
字号:
.fifo_size = 0,};static struct snd_pcm_hardware snd_sonicvibes_capture ={ .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, .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 4000, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 32, .period_bytes_max = (128*1024), .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static int snd_sonicvibes_playback_open(struct snd_pcm_substream *substream){ struct sonicvibes *sonic = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; sonic->mode |= SV_MODE_PLAY; sonic->playback_substream = substream; runtime->hw = snd_sonicvibes_playback; snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_sonicvibes_hw_constraint_dac_rate, NULL, SNDRV_PCM_HW_PARAM_RATE, -1); return 0;}static int snd_sonicvibes_capture_open(struct snd_pcm_substream *substream){ struct sonicvibes *sonic = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; sonic->mode |= SV_MODE_CAPTURE; sonic->capture_substream = substream; runtime->hw = snd_sonicvibes_capture; snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_sonicvibes_hw_constraints_adc_clock); return 0;}static int snd_sonicvibes_playback_close(struct snd_pcm_substream *substream){ struct sonicvibes *sonic = snd_pcm_substream_chip(substream); sonic->playback_substream = NULL; sonic->mode &= ~SV_MODE_PLAY; return 0;}static int snd_sonicvibes_capture_close(struct snd_pcm_substream *substream){ struct sonicvibes *sonic = snd_pcm_substream_chip(substream); sonic->capture_substream = NULL; sonic->mode &= ~SV_MODE_CAPTURE; return 0;}static struct snd_pcm_ops snd_sonicvibes_playback_ops = { .open = snd_sonicvibes_playback_open, .close = snd_sonicvibes_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_sonicvibes_hw_params, .hw_free = snd_sonicvibes_hw_free, .prepare = snd_sonicvibes_playback_prepare, .trigger = snd_sonicvibes_playback_trigger, .pointer = snd_sonicvibes_playback_pointer,};static struct snd_pcm_ops snd_sonicvibes_capture_ops = { .open = snd_sonicvibes_capture_open, .close = snd_sonicvibes_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_sonicvibes_hw_params, .hw_free = snd_sonicvibes_hw_free, .prepare = snd_sonicvibes_capture_prepare, .trigger = snd_sonicvibes_capture_trigger, .pointer = snd_sonicvibes_capture_pointer,};static int __devinit snd_sonicvibes_pcm(struct sonicvibes * sonic, int device, struct snd_pcm ** rpcm){ struct snd_pcm *pcm; int err; if ((err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm)) < 0) return err; snd_assert(pcm != NULL, return -EINVAL); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sonicvibes_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sonicvibes_capture_ops); pcm->private_data = sonic; pcm->info_flags = 0; strcpy(pcm->name, "S3 SonicVibes"); sonic->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(sonic->pci), 64*1024, 128*1024); if (rpcm) *rpcm = pcm; return 0;}/* * Mixer part */#define SONICVIBES_MUX(xname, xindex) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_sonicvibes_info_mux, \ .get = snd_sonicvibes_get_mux, .put = snd_sonicvibes_put_mux }static int snd_sonicvibes_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[7] = { "CD", "PCM", "Aux1", "Line", "Aux0", "Mic", "Mix" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 2; uinfo->value.enumerated.items = 7; if (uinfo->value.enumerated.item >= 7) uinfo->value.enumerated.item = 6; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct sonicvibes *sonic = snd_kcontrol_chip(kcontrol); spin_lock_irq(&sonic->reg_lock); ucontrol->value.enumerated.item[0] = ((snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC) & SV_RECSRC_OUT) >> 5) - 1; ucontrol->value.enumerated.item[1] = ((snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC) & SV_RECSRC_OUT) >> 5) - 1; spin_unlock_irq(&sonic->reg_lock); return 0;}static int snd_sonicvibes_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct sonicvibes *sonic = snd_kcontrol_chip(kcontrol); unsigned short left, right, oval1, oval2; int change; if (ucontrol->value.enumerated.item[0] >= 7 || ucontrol->value.enumerated.item[1] >= 7) return -EINVAL; left = (ucontrol->value.enumerated.item[0] + 1) << 5; right = (ucontrol->value.enumerated.item[1] + 1) << 5; spin_lock_irq(&sonic->reg_lock); oval1 = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC); oval2 = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC); left = (oval1 & ~SV_RECSRC_OUT) | left; right = (oval2 & ~SV_RECSRC_OUT) | right; change = left != oval1 || right != oval2; snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ADC, left); snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ADC, right); spin_unlock_irq(&sonic->reg_lock); return change;}#define SONICVIBES_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_sonicvibes_info_single, \ .get = snd_sonicvibes_get_single, .put = snd_sonicvibes_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }static int snd_sonicvibes_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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_sonicvibes_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct sonicvibes *sonic = 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; spin_lock_irq(&sonic->reg_lock); ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, reg)>> shift) & mask; spin_unlock_irq(&sonic->reg_lock); if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; return 0;}static int snd_sonicvibes_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct sonicvibes *sonic = 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 change; unsigned short val, oval; val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; val <<= shift; spin_lock_irq(&sonic->reg_lock); oval = snd_sonicvibes_in1(sonic, reg); val = (oval & ~(mask << shift)) | val; change = val != oval; snd_sonicvibes_out1(sonic, reg, val); spin_unlock_irq(&sonic->reg_lock); return change;}#define SONICVIBES_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_sonicvibes_info_double, \ .get = snd_sonicvibes_get_double, .put = snd_sonicvibes_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }static int snd_sonicvibes_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *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_sonicvibes_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct sonicvibes *sonic = 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; spin_lock_irq(&sonic->reg_lock); ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, left_reg) >> shift_left) & mask; ucontrol->value.integer.value[1] = (snd_sonicvibes_in1(sonic, right_reg) >> shift_right) & mask; spin_unlock_irq(&sonic->reg_lock); 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_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct sonicvibes *sonic = 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 short val1, val2, oval1, oval2; 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; spin_lock_irq(&sonic->reg_lock); oval1 = snd_sonicvibes_in1(sonic, left_reg); oval2 = snd_sonicvibes_in1(sonic, right_reg); val1 = (oval1 & ~(mask << shift_left)) | val1; val2 = (oval2 & ~(mask << shift_right)) | val2; change = val1 != oval1 || val2 != oval2; snd_sonicvibes_out1(sonic, left_reg, val1); snd_sonicvibes_out1(sonic, right_reg, val2); spin_unlock_irq(&sonic->reg_lock); return change;}static struct snd_kcontrol_new snd_sonicvibes_controls[] __devinitdata = {SONICVIBES_DOUBLE("Capture Volume", 0, SV_IREG_LEFT_ADC, SV_IREG_RIGHT_ADC, 0, 0, 15, 0),SONICVIBES_DOUBLE("Aux Playback Switch", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 7, 7, 1, 1),SONICVIBES_DOUBLE("Aux Playback Volume", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 0, 0, 31, 1),SONICVIBES_DOUBLE("CD Playback Switch", 0, SV_IREG_LEFT_CD, SV_IREG_RIGHT_CD, 7, 7, 1, 1),SONICVIBES_DOUBLE("CD Playback Volume", 0, SV_IREG_LEFT_CD, SV_IREG_RIGHT_CD, 0, 0, 31, 1),SONICVIBES_DOUBLE("Line Playback Switch", 0, SV_IREG_LEFT_LINE, SV_IREG_RIGHT_LINE, 7, 7, 1, 1),SONICVIBES_DOUBLE("Line Playback Volume", 0, SV_IREG_LEFT_LINE, SV_IREG_RIGHT_LINE, 0, 0, 31, 1),SONICVIBES_SINGLE("Mic Playback Switch", 0, SV_IREG_MIC, 7, 1, 1),SONICVIBES_SINGLE("Mic Playback Volume", 0, SV_IREG_MIC, 0, 15, 1),SONICVIBES_SINGLE("Mic Boost", 0, SV_IREG_LEFT_ADC, 4, 1, 0),SONICVIBES_DOUBLE("Synth Playback Switch", 0, SV_IREG_LEFT_SYNTH, SV_IREG_RIGHT_SYNTH, 7, 7, 1, 1),SONICVIBES_DOUBLE("Synth Playback Volume", 0, SV_IREG_LEFT_SYNTH, SV_IREG_RIGHT_SYNTH, 0, 0, 31, 1),SONICVIBES_DOUBLE("Aux Playback Switch", 1, SV_IREG_LEFT_AUX2, SV_IREG_RIGHT_AUX2, 7, 7, 1, 1),SONICVIBES_DOUBLE("Aux Playback Volume", 1, SV_IREG_LEFT_AUX2, SV_IREG_RIGHT_AUX2, 0, 0, 31, 1),SONICVIBES_DOUBLE("Master Playback Switch", 0, SV_IREG_LEFT_ANALOG, SV_IREG_RIGHT_ANALOG, 7, 7, 1, 1),SONICVIBES_DOUBLE("Master Playback Volume", 0, SV_IREG_LEFT_ANALOG, SV_IREG_RIGHT_ANALOG, 0, 0, 31, 1),SONICVIBES_DOUBLE("PCM Playback Switch", 0, SV_IREG_LEFT_PCM, SV_IREG_RIGHT_PCM, 7, 7, 1, 1),SONICVIBES_DOUBLE("PCM Playback Volume", 0, SV_IREG_LEFT_PCM, SV_IREG_RIGHT_PCM, 0, 0, 63, 1),SONICVIBES_SINGLE("Loopback Capture Switch", 0, SV_IREG_ADC_OUTPUT_CTRL, 0, 1, 0),SONICVIBES_SINGLE("Loopback Capture Volume", 0, SV_IREG_ADC_OUTPUT_CTRL, 2, 63, 1),SONICVIBES_MUX("Capture Source", 0)};static void snd_sonicvibes_master_free(struct snd_kcontrol *kcontrol){ struct sonicvibes *sonic = snd_kcontrol_chip(kcontrol); sonic->master_mute = NULL; sonic->master_volume = NULL;}static int __devinit snd_sonicvibes_mixer(struct sonicvibes * sonic){ struct snd_card *card; struct snd_kcontrol *kctl; unsigned int idx; int err; snd_assert(sonic != NULL && sonic->card != NULL, return -EINVAL); card = sonic->card; strcpy(card->mixername, "S3 SonicVibes"); for (idx = 0; idx < ARRAY_SIZE(snd_sonicvibes_controls); idx++) { if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_sonicvibes_controls[idx], sonic))) < 0) return err; switch (idx) { case 0: case 1: kctl->private_free = snd_sonicvibes_master_free; break; } } return 0;}/* */static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct sonicvibes *sonic = entry->private_data; unsigned char tmp; tmp = sonic->srs_space & 0x0f; snd_iprintf(buffer, "SRS 3D : %s\n", sonic->srs_space & 0x80 ? "off" : "on"); snd_iprintf(buffer, "SRS Space : %s\n", tmp == 0x00 ? "100%" : tmp == 0x01 ? "75%" : tmp == 0x02 ? "50%" : tmp == 0x03 ? "25%" : "0%"); tmp = sonic->srs_center & 0x0f; snd_iprintf(buffer, "SRS Center : %s\n", tmp == 0x00 ? "100%" : tmp == 0x01 ? "75%" : tmp == 0x02 ? "50%" : tmp == 0x03 ? "25%" : "0%"); tmp = sonic->wave_source & 0x03; snd_iprintf(buffer, "WaveTable Source : %s\n", tmp == 0x00 ? "on-board ROM" : tmp == 0x01 ? "PCI bus" : "on-board ROM + PCI bus"); tmp = sonic->mpu_switch; snd_iprintf(buffer, "Onboard synth : %s\n", tmp & 0x01 ? "on" : "off");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -