📄 ice1712.c
字号:
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_ops); pcm->private_data = ice; pcm->private_free = snd_ice1712_pcm_free; pcm->info_flags = 0; strcpy(pcm->name, "ICE1712 consumer"); ice->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 64*1024); if (rpcm) *rpcm = pcm; printk(KERN_WARNING "Consumer PCM code does not work well at the moment --jk\n"); return 0;}static void snd_ice1712_pcm_free_ds(snd_pcm_t *pcm){ ice1712_t *ice = pcm->private_data; ice->pcm_ds = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}static int __devinit snd_ice1712_pcm_ds(ice1712_t * ice, int device, snd_pcm_t ** rpcm){ snd_pcm_t *pcm; int err; if (rpcm) *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 consumer (DS)", device, 6, 0, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_ds_ops); pcm->private_data = ice; pcm->private_free = snd_ice1712_pcm_free_ds; pcm->info_flags = 0; strcpy(pcm->name, "ICE1712 consumer (DS)"); ice->pcm_ds = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 128*1024); if (rpcm) *rpcm = pcm; return 0;}/* * PCM code - professional part (multitrack) */static unsigned int rates[] = { 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000 };static snd_pcm_hw_constraint_list_t hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0,};static int snd_ice1712_pro_trigger(snd_pcm_substream_t *substream, int cmd){ ice1712_t *ice = snd_pcm_substream_chip(substream); switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: { unsigned int what; unsigned int old; if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return -EINVAL; what = ICE1712_PLAYBACK_PAUSE; snd_pcm_trigger_done(substream, substream); spin_lock(&ice->reg_lock); old = inl(ICEMT(ice, PLAYBACK_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) old |= what; else old &= ~what; outl(old, ICEMT(ice, PLAYBACK_CONTROL)); spin_unlock(&ice->reg_lock); break; } case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; unsigned int old; struct list_head *pos; snd_pcm_substream_t *s; snd_pcm_group_for_each(pos, substream) { s = snd_pcm_group_substream_entry(pos); if (s == ice->playback_pro_substream) { what |= ICE1712_PLAYBACK_START; snd_pcm_trigger_done(s, substream); } else if (s == ice->capture_pro_substream) { what |= ICE1712_CAPTURE_START_SHADOW; snd_pcm_trigger_done(s, substream); } } spin_lock(&ice->reg_lock); old = inl(ICEMT(ice, PLAYBACK_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_START) old |= what; else old &= ~what; outl(old, ICEMT(ice, PLAYBACK_CONTROL)); spin_unlock(&ice->reg_lock); break; } default: return -EINVAL; } return 0;}/* */static void snd_ice1712_set_pro_rate(ice1712_t *ice, unsigned int rate, int force){ unsigned long flags; unsigned char val, old; unsigned int i; switch (rate) { case 8000: val = 6; break; case 9600: val = 3; break; case 11025: val = 10; break; case 12000: val = 2; break; case 16000: val = 5; break; case 22050: val = 9; break; case 24000: val = 1; break; case 32000: val = 4; break; case 44100: val = 8; break; case 48000: val = 0; break; case 64000: val = 15; break; case 88200: val = 11; break; case 96000: val = 7; break; default: snd_BUG(); val = 0; rate = 48000; break; } spin_lock_irqsave(&ice->reg_lock, flags); if (inb(ICEMT(ice, PLAYBACK_CONTROL)) & (ICE1712_CAPTURE_START_SHADOW| ICE1712_PLAYBACK_PAUSE| ICE1712_PLAYBACK_START)) { __out: spin_unlock_irqrestore(&ice->reg_lock, flags); return; } if (!force && is_pro_rate_locked(ice)) goto __out; old = inb(ICEMT(ice, RATE)); if (!force && old == val) goto __out; outb(val, ICEMT(ice, RATE)); spin_unlock_irqrestore(&ice->reg_lock, flags); if (ice->gpio.set_pro_rate) ice->gpio.set_pro_rate(ice, rate); for (i = 0; i < ice->akm_codecs; i++) { if (ice->akm[i].ops.set_rate_val) ice->akm[i].ops.set_rate_val(&ice->akm[i], rate); } if (ice->spdif.ops.setup_rate) ice->spdif.ops.setup_rate(ice, rate);}static int snd_ice1712_playback_pro_prepare(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); ice->playback_pro_size = snd_pcm_lib_buffer_bytes(substream); spin_lock_irq(&ice->reg_lock); outl(substream->runtime->dma_addr, ICEMT(ice, PLAYBACK_ADDR)); outw((ice->playback_pro_size >> 2) - 1, ICEMT(ice, PLAYBACK_SIZE)); outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, PLAYBACK_COUNT)); spin_unlock_irq(&ice->reg_lock); return 0;}static int snd_ice1712_playback_pro_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_ice1712_capture_pro_prepare(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); ice->capture_pro_size = snd_pcm_lib_buffer_bytes(substream); spin_lock_irq(&ice->reg_lock); outl(substream->runtime->dma_addr, ICEMT(ice, CAPTURE_ADDR)); outw((ice->capture_pro_size >> 2) - 1, ICEMT(ice, CAPTURE_SIZE)); outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ICEMT(ice, CAPTURE_COUNT)); spin_unlock_irq(&ice->reg_lock); return 0;}static int snd_ice1712_capture_pro_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_ice1712_set_pro_rate(ice, params_rate(hw_params), 0); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); size_t ptr; if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START)) return 0; ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2); if (ptr == substream->runtime->buffer_size) ptr = 0; return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); size_t ptr; if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW)) return 0; ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2); if (ptr == substream->runtime->buffer_size) ptr = 0; return bytes_to_frames(substream->runtime, ptr);}static snd_pcm_hardware_t snd_ice1712_playback_pro ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000, .rate_min = 4000, .rate_max = 96000, .channels_min = 10, .channels_max = 10, .buffer_bytes_max = (256*1024), .period_bytes_min = 10 * 4 * 2, .period_bytes_max = 131040, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static snd_pcm_hardware_t snd_ice1712_capture_pro ={ .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), .formats = SNDRV_PCM_FMTBIT_S32_LE, .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000, .rate_min = 4000, .rate_max = 96000, .channels_min = 12, .channels_max = 12, .buffer_bytes_max = (256*1024), .period_bytes_min = 12 * 4 * 2, .period_bytes_max = 131040, .periods_min = 1, .periods_max = 1024, .fifo_size = 0,};static int snd_ice1712_playback_pro_open(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; ice1712_t *ice = snd_pcm_substream_chip(substream); ice->playback_pro_substream = substream; runtime->hw = snd_ice1712_playback_pro; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if (ice->spdif.ops.open) ice->spdif.ops.open(ice, substream); return 0;}static int snd_ice1712_capture_pro_open(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; ice->capture_pro_substream = substream; runtime->hw = snd_ice1712_capture_pro; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); return 0;}static int snd_ice1712_playback_pro_close(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); if (PRO_RATE_RESET) snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); ice->playback_pro_substream = NULL; if (ice->spdif.ops.close) ice->spdif.ops.close(ice, substream); return 0;}static int snd_ice1712_capture_pro_close(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); if (PRO_RATE_RESET) snd_ice1712_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); ice->capture_pro_substream = NULL; return 0;}static void snd_ice1712_pcm_profi_free(snd_pcm_t *pcm){ ice1712_t *ice = pcm->private_data; ice->pcm_pro = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}static snd_pcm_ops_t snd_ice1712_playback_pro_ops = { .open = snd_ice1712_playback_pro_open, .close = snd_ice1712_playback_pro_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_ice1712_playback_pro_hw_params, .hw_free = snd_ice1712_hw_free, .prepare = snd_ice1712_playback_pro_prepare, .trigger = snd_ice1712_pro_trigger, .pointer = snd_ice1712_playback_pro_pointer,};static snd_pcm_ops_t snd_ice1712_capture_pro_ops = { .open = snd_ice1712_capture_pro_open, .close = snd_ice1712_capture_pro_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_ice1712_capture_pro_hw_params, .hw_free = snd_ice1712_hw_free, .prepare = snd_ice1712_capture_pro_prepare, .trigger = snd_ice1712_pro_trigger, .pointer = snd_ice1712_capture_pro_pointer,};static int __devinit snd_ice1712_pcm_profi(ice1712_t * ice, int device, snd_pcm_t ** rpcm){ snd_pcm_t *pcm; int err; if (rpcm) *rpcm = NULL; err = snd_pcm_new(ice->card, "ICE1712 multi", device, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ice1712_playback_pro_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ice1712_capture_pro_ops); pcm->private_data = ice; pcm->private_free = snd_ice1712_pcm_profi_free; pcm->info_flags = 0; strcpy(pcm->name, "ICE1712 multi"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 256*1024, 256*1024); ice->pcm_pro = pcm; if (rpcm) *rpcm = pcm; if (ice->cs8427) { /* assign channels to iec958 */ err = snd_cs8427_iec958_build(ice->cs8427, pcm->streams[0].substream, pcm->streams[1].substream); if (err < 0) return err; } if ((err = snd_ice1712_build_pro_mixer(ice)) < 0) return err; return 0;}/* * Mixer section */static void snd_ice1712_update_volume(ice1712_t *ice, int index){ unsigned int vol = ice->pro_volumes[index]; unsigned short val = 0; val |= (vol & 0x8000) == 0 ? (96 - (vol & 0x7f)) : 0x7f; val |= ((vol & 0x80000000) == 0 ? (96 - ((vol >> 16) & 0x7f)) : 0x7f) << 8; outb(index, ICEMT(ice, MONITOR_INDEX)); outw(val, ICEMT(ice, MONITOR_VOLUME));}static int snd_ice1712_pro_mixer_switch_info(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_ice1712_pro_mixer_switch_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -