📄 cs4231.c
字号:
snd_cs4231_mce_down(chip); spin_lock_irqsave(&chip->lock, flags); for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */ snd_cs4231_out(chip, i, *ptr++); spin_unlock_irqrestore(&chip->lock, flags); snd_cs4231_mce_up(chip); snd_cs4231_mce_down(chip); mdelay(2); return 0; /* all things are ok.. */}static struct snd_pcm_hardware snd_cs4231_playback = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START, .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rate_min = 5510, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 32 * 1024, .period_bytes_min = 64, .period_bytes_max = 32 * 1024, .periods_min = 1, .periods_max = 1024,};static struct snd_pcm_hardware snd_cs4231_capture = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START, .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_IMA_ADPCM | SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000, .rate_min = 5510, .rate_max = 48000, .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 32 * 1024, .period_bytes_min = 64, .period_bytes_max = 32 * 1024, .periods_min = 1, .periods_max = 1024,};static int snd_cs4231_playback_open(struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; runtime->hw = snd_cs4231_playback; err = snd_cs4231_open(chip, CS4231_MODE_PLAY); if (err < 0) { snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } chip->playback_substream = substream; chip->p_periods_sent = 0; snd_pcm_set_sync(substream); snd_cs4231_xrate(runtime); return 0;}static int snd_cs4231_capture_open(struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; runtime->hw = snd_cs4231_capture; err = snd_cs4231_open(chip, CS4231_MODE_RECORD); if (err < 0) { snd_free_pages(runtime->dma_area, runtime->dma_bytes); return err; } chip->capture_substream = substream; chip->c_periods_sent = 0; snd_pcm_set_sync(substream); snd_cs4231_xrate(runtime); return 0;}static int snd_cs4231_playback_close(struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); snd_cs4231_close(chip, CS4231_MODE_PLAY); chip->playback_substream = NULL; return 0;}static int snd_cs4231_capture_close(struct snd_pcm_substream *substream){ struct snd_cs4231 *chip = snd_pcm_substream_chip(substream); snd_cs4231_close(chip, CS4231_MODE_RECORD); chip->capture_substream = NULL; return 0;}/* XXX We can do some power-management, in particular on EBUS using * XXX the audio AUXIO register... */static struct snd_pcm_ops snd_cs4231_playback_ops = { .open = snd_cs4231_playback_open, .close = snd_cs4231_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4231_playback_hw_params, .hw_free = snd_pcm_lib_free_pages, .prepare = snd_cs4231_playback_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_playback_pointer,};static struct snd_pcm_ops snd_cs4231_capture_ops = { .open = snd_cs4231_capture_open, .close = snd_cs4231_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4231_capture_hw_params, .hw_free = snd_pcm_lib_free_pages, .prepare = snd_cs4231_capture_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_capture_pointer,};static int __init snd_cs4231_pcm(struct snd_card *card){ struct snd_cs4231 *chip = card->private_data; struct snd_pcm *pcm; int err; err = snd_pcm_new(card, "CS4231", 0, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4231_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4231_capture_ops); /* global setup */ pcm->private_data = chip; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; strcpy(pcm->name, "CS4231"); chip->p_dma.preallocate(chip, pcm); chip->pcm = pcm; return 0;}static int __init snd_cs4231_timer(struct snd_card *card){ struct snd_cs4231 *chip = card->private_data; struct snd_timer *timer; struct snd_timer_id tid; int err; /* Timer initialization */ tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = card->number; tid.device = 0; tid.subdevice = 0; err = snd_timer_new(card, "CS4231", &tid, &timer); if (err < 0) return err; strcpy(timer->name, "CS4231"); timer->private_data = chip; timer->hw = snd_cs4231_timer_table; chip->timer = timer; return 0;}/* * MIXER part */static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ static char *texts[4] = { "Line", "CD", "Mic", "Mix" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 2; uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); return 0;}static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; spin_lock_irqsave(&chip->lock, flags); ucontrol->value.enumerated.item[0] = (chip->image[CS4231_LEFT_INPUT] & CS4231_MIXS_ALL) >> 6; ucontrol->value.enumerated.item[1] = (chip->image[CS4231_RIGHT_INPUT] & CS4231_MIXS_ALL) >> 6; spin_unlock_irqrestore(&chip->lock, flags); return 0;}static int snd_cs4231_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; unsigned short left, right; int change; if (ucontrol->value.enumerated.item[0] > 3 || ucontrol->value.enumerated.item[1] > 3) return -EINVAL; left = ucontrol->value.enumerated.item[0] << 6; right = ucontrol->value.enumerated.item[1] << 6; spin_lock_irqsave(&chip->lock, flags); left = (chip->image[CS4231_LEFT_INPUT] & ~CS4231_MIXS_ALL) | left; right = (chip->image[CS4231_RIGHT_INPUT] & ~CS4231_MIXS_ALL) | right; change = left != chip->image[CS4231_LEFT_INPUT] || right != chip->image[CS4231_RIGHT_INPUT]; snd_cs4231_out(chip, CS4231_LEFT_INPUT, left); snd_cs4231_out(chip, CS4231_RIGHT_INPUT, right); spin_unlock_irqrestore(&chip->lock, flags); return change;}static int snd_cs4231_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_cs4231_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; 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_irqsave(&chip->lock, flags); ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask; spin_unlock_irqrestore(&chip->lock, flags); if (invert) ucontrol->value.integer.value[0] = (mask - ucontrol->value.integer.value[0]); return 0;}static int snd_cs4231_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; 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; val = (ucontrol->value.integer.value[0] & mask); if (invert) val = mask - val; val <<= shift; spin_lock_irqsave(&chip->lock, flags); val = (chip->image[reg] & ~(mask << shift)) | val; change = val != chip->image[reg]; snd_cs4231_out(chip, reg, val); spin_unlock_irqrestore(&chip->lock, flags); return change;}static int snd_cs4231_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_cs4231_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; 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_irqsave(&chip->lock, flags); ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask; ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask; spin_unlock_irqrestore(&chip->lock, flags); 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_cs4231_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_cs4231 *chip = snd_kcontrol_chip(kcontrol); unsigned long flags; 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; 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_irqsave(&chip->lock, flags); val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; change = val1 != chip->image[left_reg]; change |= val2 != chip->image[right_reg]; snd_cs4231_out(chip, left_reg, val1); snd_cs4231_out(chip, right_reg, val2); spin_unlock_irqrestore(&chip->lock, flags); return change;}#define CS4231_SINGLE(xname, xindex, reg, shift, mask, invert) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), .index = (xindex), \ .info = snd_cs4231_info_single, \ .get = snd_cs4231_get_single, .put = snd_cs4231_put_single, \ .private_value = (reg) | ((shift) << 8) | ((mask) << 16) | ((invert) << 24) }#define CS4231_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_cs4231_info_double, \ .get = snd_cs4231_get_double, .put = snd_cs4231_put_double, \ .private_value = (left_reg) | ((right_reg) << 8) | ((shift_left) << 16) | \ ((shift_right) << 19) | ((mask) << 24) | ((invert) << 22) }static struct snd_kcontrol_new snd_cs4231_controls[] __initdata = {CS4231_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),CS4231_DOUBLE("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1),CS4231_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1),CS4231_DOUBLE("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1),CS4231_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),CS4231_DOUBLE("Aux Playback Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1),CS4231_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),CS4231_DOUBLE("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1),CS4231_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1),CS4231_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1),CS4231_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1),CS4231_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0),CS4231_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0),{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", .info = snd_cs4231_info_mux, .get = snd_cs4231_get_mux, .put = snd_cs4231_put_mux,},CS4231_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0),CS4231_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),CS4231_SINGLE("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1),/* SPARC specific uses of XCTL{0,1} general purpose outputs. */CS4231_SINGLE("Line Out Switch", 0, CS4231_PIN_CTRL, 6, 1, 1),CS4231_SINGLE("Headphone Out Switch", 0, CS4231_PIN_CTRL, 7, 1, 1)};static int __init snd_cs4231_mixer(struct snd_card *card){ struct snd_cs4231 *chip = card->private_data; int err, idx; snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL); strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_cs4231_controls); idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4231_controls[idx], chip)); if (err < 0) return err; } return 0;}static int dev;static int __init cs4231_attach_begin(struct snd_card **rcard){ struct snd_card *card; struct snd_cs4231 *chip; *rcard = NULL; if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_cs4231)); if (card == NULL) return -ENOMEM; strcpy(card->driver, "CS4231"); strcpy(card->shortname, "Sun CS4231"); chip = card->private_data; chip->card = card; *rcard = card; return 0;}static int __init cs4231_attach_finish(struct snd_card *card){ struct snd_cs4231 *chip = card->private_data; int err; err = snd_cs4231_pcm(card); if (err < 0) goto out_err; err = snd_cs4231_mixer(card); if (err < 0) goto out_err; err = snd_cs4231_timer(card); if (err < 0) goto out_err; err = snd_card_register(card); if (err < 0) goto out_err;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -