📄 cs4281.c
字号:
static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream){ struct snd_pcm_runtime *runtime = substream->runtime; struct cs4281_dma *dma = runtime->private_data; struct cs4281 *chip = snd_pcm_substream_chip(substream); // printk("DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies); return runtime->buffer_size - snd_cs4281_peekBA0(chip, dma->regDCC) - 1;}static struct snd_pcm_hardware snd_cs4281_playback ={ .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE, .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 = (512*1024), .period_bytes_min = 64, .period_bytes_max = (512*1024), .periods_min = 1, .periods_max = 2, .fifo_size = CS4281_FIFO_SIZE,};static struct snd_pcm_hardware snd_cs4281_capture ={ .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_BE | SNDRV_PCM_FMTBIT_S16_BE | SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_BE | SNDRV_PCM_FMTBIT_S32_BE, .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 = (512*1024), .period_bytes_min = 64, .period_bytes_max = (512*1024), .periods_min = 1, .periods_max = 2, .fifo_size = CS4281_FIFO_SIZE,};static int snd_cs4281_playback_open(struct snd_pcm_substream *substream){ struct cs4281 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct cs4281_dma *dma; dma = &chip->dma[0]; dma->substream = substream; dma->left_slot = 0; dma->right_slot = 1; runtime->private_data = dma; runtime->hw = snd_cs4281_playback; /* should be detected from the AC'97 layer, but it seems that although CS4297A rev B reports 18-bit ADC resolution, samples are 20-bit */ snd_pcm_hw_constraint_msbits(runtime, 0, 32, 20); return 0;}static int snd_cs4281_capture_open(struct snd_pcm_substream *substream){ struct cs4281 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct cs4281_dma *dma; dma = &chip->dma[1]; dma->substream = substream; dma->left_slot = 10; dma->right_slot = 11; runtime->private_data = dma; runtime->hw = snd_cs4281_capture; /* should be detected from the AC'97 layer, but it seems that although CS4297A rev B reports 18-bit ADC resolution, samples are 20-bit */ snd_pcm_hw_constraint_msbits(runtime, 0, 32, 20); return 0;}static int snd_cs4281_playback_close(struct snd_pcm_substream *substream){ struct cs4281_dma *dma = substream->runtime->private_data; dma->substream = NULL; return 0;}static int snd_cs4281_capture_close(struct snd_pcm_substream *substream){ struct cs4281_dma *dma = substream->runtime->private_data; dma->substream = NULL; return 0;}static struct snd_pcm_ops snd_cs4281_playback_ops = { .open = snd_cs4281_playback_open, .close = snd_cs4281_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4281_hw_params, .hw_free = snd_cs4281_hw_free, .prepare = snd_cs4281_playback_prepare, .trigger = snd_cs4281_trigger, .pointer = snd_cs4281_pointer,};static struct snd_pcm_ops snd_cs4281_capture_ops = { .open = snd_cs4281_capture_open, .close = snd_cs4281_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_cs4281_hw_params, .hw_free = snd_cs4281_hw_free, .prepare = snd_cs4281_capture_prepare, .trigger = snd_cs4281_trigger, .pointer = snd_cs4281_pointer,};static int __devinit snd_cs4281_pcm(struct cs4281 * chip, int device, struct snd_pcm ** rpcm){ struct snd_pcm *pcm; int err; if (rpcm) *rpcm = NULL; err = snd_pcm_new(chip->card, "CS4281", device, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs4281_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cs4281_capture_ops); pcm->private_data = chip; pcm->info_flags = 0; strcpy(pcm->name, "CS4281"); chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 512*1024); if (rpcm) *rpcm = pcm; return 0;}/* * Mixer section */#define CS_VOL_MASK 0x1fstatic int snd_cs4281_info_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = CS_VOL_MASK; return 0;} static int snd_cs4281_get_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct cs4281 *chip = snd_kcontrol_chip(kcontrol); int regL = (kcontrol->private_value >> 16) & 0xffff; int regR = kcontrol->private_value & 0xffff; int volL, volR; volL = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regL) & CS_VOL_MASK); volR = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regR) & CS_VOL_MASK); ucontrol->value.integer.value[0] = volL; ucontrol->value.integer.value[1] = volR; return 0;}static int snd_cs4281_put_volume(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct cs4281 *chip = snd_kcontrol_chip(kcontrol); int change = 0; int regL = (kcontrol->private_value >> 16) & 0xffff; int regR = kcontrol->private_value & 0xffff; int volL, volR; volL = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regL) & CS_VOL_MASK); volR = CS_VOL_MASK - (snd_cs4281_peekBA0(chip, regR) & CS_VOL_MASK); if (ucontrol->value.integer.value[0] != volL) { volL = CS_VOL_MASK - (ucontrol->value.integer.value[0] & CS_VOL_MASK); snd_cs4281_pokeBA0(chip, regL, volL); change = 1; } if (ucontrol->value.integer.value[1] != volR) { volR = CS_VOL_MASK - (ucontrol->value.integer.value[1] & CS_VOL_MASK); snd_cs4281_pokeBA0(chip, regR, volR); change = 1; } return change;}static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -4650, 150, 0);static struct snd_kcontrol_new snd_cs4281_fm_vol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Synth Playback Volume", .info = snd_cs4281_info_volume, .get = snd_cs4281_get_volume, .put = snd_cs4281_put_volume, .private_value = ((BA0_FMLVC << 16) | BA0_FMRVC), .tlv = { .p = db_scale_dsp },};static struct snd_kcontrol_new snd_cs4281_pcm_vol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Stream Playback Volume", .info = snd_cs4281_info_volume, .get = snd_cs4281_get_volume, .put = snd_cs4281_put_volume, .private_value = ((BA0_PPLVC << 16) | BA0_PPRVC), .tlv = { .p = db_scale_dsp },};static void snd_cs4281_mixer_free_ac97_bus(struct snd_ac97_bus *bus){ struct cs4281 *chip = bus->private_data; chip->ac97_bus = NULL;}static void snd_cs4281_mixer_free_ac97(struct snd_ac97 *ac97){ struct cs4281 *chip = ac97->private_data; if (ac97->num) chip->ac97_secondary = NULL; else chip->ac97 = NULL;}static int __devinit snd_cs4281_mixer(struct cs4281 * chip){ struct snd_card *card = chip->card; struct snd_ac97_template ac97; int err; static struct snd_ac97_bus_ops ops = { .write = snd_cs4281_ac97_write, .read = snd_cs4281_ac97_read, }; if ((err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus)) < 0) return err; chip->ac97_bus->private_free = snd_cs4281_mixer_free_ac97_bus; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_cs4281_mixer_free_ac97; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; if (chip->dual_codec) { ac97.num = 1; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97_secondary)) < 0) return err; } if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_fm_vol, chip))) < 0) return err; if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_cs4281_pcm_vol, chip))) < 0) return err; return 0;}/* * proc interface */static void snd_cs4281_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct cs4281 *chip = entry->private_data; snd_iprintf(buffer, "Cirrus Logic CS4281\n\n"); snd_iprintf(buffer, "Spurious half IRQs : %u\n", chip->spurious_dhtc_irq); snd_iprintf(buffer, "Spurious end IRQs : %u\n", chip->spurious_dtc_irq);}static long snd_cs4281_BA0_read(struct snd_info_entry *entry, void *file_private_data, struct file *file, char __user *buf, unsigned long count, unsigned long pos){ long size; struct cs4281 *chip = entry->private_data; size = count; if (pos + size > CS4281_BA0_SIZE) size = (long)CS4281_BA0_SIZE - pos; if (size > 0) { if (copy_to_user_fromio(buf, chip->ba0 + pos, size)) return -EFAULT; } return size;}static long snd_cs4281_BA1_read(struct snd_info_entry *entry, void *file_private_data, struct file *file, char __user *buf, unsigned long count, unsigned long pos){ long size; struct cs4281 *chip = entry->private_data; size = count; if (pos + size > CS4281_BA1_SIZE) size = (long)CS4281_BA1_SIZE - pos; if (size > 0) { if (copy_to_user_fromio(buf, chip->ba1 + pos, size)) return -EFAULT; } return size;}static struct snd_info_entry_ops snd_cs4281_proc_ops_BA0 = { .read = snd_cs4281_BA0_read,};static struct snd_info_entry_ops snd_cs4281_proc_ops_BA1 = { .read = snd_cs4281_BA1_read,};static void __devinit snd_cs4281_proc_init(struct cs4281 * chip){ struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "cs4281", &entry)) snd_info_set_text_ops(entry, chip, snd_cs4281_proc_read); if (! snd_card_proc_new(chip->card, "cs4281_BA0", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = chip; entry->c.ops = &snd_cs4281_proc_ops_BA0; entry->size = CS4281_BA0_SIZE; } if (! snd_card_proc_new(chip->card, "cs4281_BA1", &entry)) { entry->content = SNDRV_INFO_CONTENT_DATA; entry->private_data = chip; entry->c.ops = &snd_cs4281_proc_ops_BA1; entry->size = CS4281_BA1_SIZE; }}/* * joystick support */#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))static void snd_cs4281_gameport_trigger(struct gameport *gameport){ struct cs4281 *chip = gameport_get_port_data(gameport); snd_assert(chip, return); snd_cs4281_pokeBA0(chip, BA0_JSPT, 0xff);}static unsigned char snd_cs4281_gameport_read(struct gameport *gameport){ struct cs4281 *chip = gameport_get_port_data(gameport); snd_assert(chip, return 0); return snd_cs4281_peekBA0(chip, BA0_JSPT);}#ifdef COOKED_MODEstatic int snd_cs4281_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons){ struct cs4281 *chip = gameport_get_port_data(gameport); unsigned js1, js2, jst; snd_assert(chip, return 0); js1 = snd_cs4281_peekBA0(chip, BA0_JSC1); js2 = snd_cs4281_peekBA0(chip, BA0_JSC2); jst = snd_cs4281_peekBA0(chip, BA0_JSPT); *buttons = (~jst >> 4) & 0x0F; axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF; axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF; axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF; axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF; for (jst = 0; jst < 4; ++jst)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -