cs4231.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,248 行 · 第 1/5 页
C
2,248 行
snd_printdd("cs4231: port = 0x%lx, id = 0x%x\n", chip->port, id); if (id != 0x0a) return -ENODEV; /* no valid device found */ spin_lock_irqsave(&chip->lock, flags); /* Reset DMA engine. */#ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { /* Done by ebus_dma_register */ } else {#endif#ifdef SBUS_SUPPORT sbus_writel(APC_CHIP_RESET, chip->port + APCCSR); sbus_writel(0x00, chip->port + APCCSR); sbus_writel(sbus_readl(chip->port + APCCSR) | APC_CDC_RESET, chip->port + APCCSR); udelay(20); sbus_writel(sbus_readl(chip->port + APCCSR) & ~APC_CDC_RESET, chip->port + APCCSR); sbus_writel(sbus_readl(chip->port + APCCSR) | (APC_XINT_ENA | APC_XINT_PENA | APC_XINT_CENA), chip->port + APCCSR);#endif#ifdef EBUS_SUPPORT }#endif __cs4231_readb(chip, CS4231P(chip, STATUS)); /* clear any pendings IRQ */ __cs4231_writeb(chip, 0, CS4231P(chip, STATUS)); mb(); spin_unlock_irqrestore(&chip->lock, flags); chip->image[CS4231_MISC_INFO] = CS4231_MODE2; chip->image[CS4231_IFACE_CTRL] = chip->image[CS4231_IFACE_CTRL] & ~CS4231_SINGLE_DMA; chip->image[CS4231_ALT_FEATURE_1] = 0x80; chip->image[CS4231_ALT_FEATURE_2] = 0x01; if (vers & 0x20) chip->image[CS4231_ALT_FEATURE_2] |= 0x02; ptr = (unsigned char *) &chip->image; 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 snd_pcm_hardware_t 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 = 4096, .period_bytes_max = (32*1024), .periods_min = 1, .periods_max = 1024,};static snd_pcm_hardware_t 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 = 4096, .period_bytes_max = (32*1024), .periods_min = 1, .periods_max = 1024,};static int snd_cs4231_playback_open(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; runtime->hw = snd_cs4231_playback; if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 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(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; int err; runtime->hw = snd_cs4231_capture; if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 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(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); chip->playback_substream = NULL; snd_cs4231_close(chip, CS4231_MODE_PLAY); return 0;}static int snd_cs4231_capture_close(snd_pcm_substream_t *substream){ cs4231_t *chip = snd_pcm_substream_chip(substream); chip->capture_substream = NULL; snd_cs4231_close(chip, CS4231_MODE_RECORD); return 0;}/* XXX We can do some power-management, in particular on EBUS using * XXX the audio AUXIO register... */static snd_pcm_ops_t 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_cs4231_playback_hw_free, .prepare = snd_cs4231_playback_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_playback_pointer,};static snd_pcm_ops_t 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_cs4231_capture_hw_free, .prepare = snd_cs4231_capture_prepare, .trigger = snd_cs4231_trigger, .pointer = snd_cs4231_capture_pointer,};static void snd_cs4231_pcm_free(snd_pcm_t *pcm){ cs4231_t *chip = pcm->private_data; chip->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}int snd_cs4231_pcm(cs4231_t *chip){ snd_pcm_t *pcm; int err; if ((err = snd_pcm_new(chip->card, "CS4231", 0, 1, 1, &pcm)) < 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->private_free = snd_cs4231_pcm_free; pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; strcpy(pcm->name, "CS4231");#ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->dev_u.pdev), 64*1024, 128*1024); } else {#endif#ifdef SBUS_SUPPORT snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, snd_dma_sbus_data(chip->dev_u.sdev), 64*1024, 128*1024);#endif#ifdef EBUS_SUPPORT }#endif chip->pcm = pcm; return 0;}static void snd_cs4231_timer_free(snd_timer_t *timer){ cs4231_t *chip = timer->private_data; chip->timer = NULL;}int snd_cs4231_timer(cs4231_t *chip){ snd_timer_t *timer; snd_timer_id_t tid; int err; /* Timer initialization */ tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = chip->card->number; tid.device = 0; tid.subdevice = 0; if ((err = snd_timer_new(chip->card, "CS4231", &tid, &timer)) < 0) return err; strcpy(timer->name, "CS4231"); timer->private_data = chip; timer->private_free = snd_cs4231_timer_free; timer->hw = snd_cs4231_timer_table; chip->timer = timer; return 0;} /* * MIXER part */static int snd_cs4231_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){ static char *texts[4] = { "Line", "CD", "Mic", "Mix" }; cs4231_t *chip = snd_kcontrol_chip(kcontrol); snd_assert(chip->card != NULL, return -EINVAL); 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(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs4231_t *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(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs4231_t *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;}int snd_cs4231_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;}int snd_cs4231_get_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs4231_t *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;}int snd_cs4231_put_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs4231_t *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;}int snd_cs4231_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;}int snd_cs4231_get_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs4231_t *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;}int snd_cs4231_put_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol){ cs4231_t *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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?