📄 ice1724.c
字号:
outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); spin_unlock_irqrestore(&ice->reg_lock, flags); mdelay(5); spin_lock_irqsave(&ice->reg_lock, flags); /* deassert PRST# */ outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); } } } spin_unlock_irqrestore(&ice->reg_lock, flags); /* set up codecs */ 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); }}static int snd_vt1724_pcm_hw_params(snd_pcm_substream_t * substream, snd_pcm_hw_params_t * hw_params){ ice1712_t *ice = snd_pcm_substream_chip(substream); int i, chs; chs = params_channels(hw_params); down(&ice->open_mutex); /* mark surround channels */ if (substream == ice->playback_pro_substream) { /* PDMA0 can be multi-channel up to 8 */ chs = chs / 2 - 1; for (i = 0; i < chs; i++) { if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) { up(&ice->open_mutex); return -EBUSY; } ice->pcm_reserved[i] = substream; } for (; i < 3; i++) { if (ice->pcm_reserved[i] == substream) ice->pcm_reserved[i] = NULL; } } else { for (i = 0; i < 3; i++) { /* check individual playback stream */ if (ice->playback_con_substream_ds[i] == substream) { if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) { up(&ice->open_mutex); return -EBUSY; } ice->pcm_reserved[i] = substream; break; } } } up(&ice->open_mutex); snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));}static int snd_vt1724_pcm_hw_free(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); int i; down(&ice->open_mutex); /* unmark surround channels */ for (i = 0; i < 3; i++) if (ice->pcm_reserved[i] == substream) ice->pcm_reserved[i] = NULL; up(&ice->open_mutex); return snd_pcm_lib_free_pages(substream);}static int snd_vt1724_playback_pro_prepare(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); unsigned char val; unsigned int size; spin_lock_irq(&ice->reg_lock); val = (8 - substream->runtime->channels) >> 1; outb(val, ICEMT1724(ice, BURST)); outl(substream->runtime->dma_addr, ICEMT1724(ice, PLAYBACK_ADDR)); size = (snd_pcm_lib_buffer_bytes(substream) >> 2) - 1; // outl(size, ICEMT1724(ice, PLAYBACK_SIZE)); outw(size, ICEMT1724(ice, PLAYBACK_SIZE)); outb(size >> 16, ICEMT1724(ice, PLAYBACK_SIZE) + 2); size = (snd_pcm_lib_period_bytes(substream) >> 2) - 1; // outl(size, ICEMT1724(ice, PLAYBACK_COUNT)); outw(size, ICEMT1724(ice, PLAYBACK_COUNT)); outb(size >> 16, ICEMT1724(ice, PLAYBACK_COUNT) + 2); spin_unlock_irq(&ice->reg_lock); // printk("pro prepare: ch = %d, addr = 0x%x, buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, snd_pcm_lib_buffer_bytes(substream), snd_pcm_lib_period_bytes(substream)); return 0;}static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); size_t ptr; if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & VT1724_PDMA0_START)) return 0;#if 0 /* read PLAYBACK_ADDR */ ptr = inl(ICEMT1724(ice, PLAYBACK_ADDR)); if (ptr < substream->runtime->dma_addr) { snd_printd("ice1724: invalid negative ptr\n"); return 0; } ptr -= substream->runtime->dma_addr; ptr = bytes_to_frames(substream->runtime, ptr); if (ptr >= substream->runtime->buffer_size) { snd_printd("ice1724: invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->period_size); return 0; }#else /* read PLAYBACK_SIZE */ ptr = inl(ICEMT1724(ice, PLAYBACK_SIZE)) & 0xffffff; ptr = (ptr + 1) << 2; ptr = bytes_to_frames(substream->runtime, ptr); if (! ptr) ; else if (ptr <= substream->runtime->buffer_size) ptr = substream->runtime->buffer_size - ptr; else { snd_printd("ice1724: invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->buffer_size); ptr = 0; }#endif return ptr;}static int snd_vt1724_pcm_prepare(snd_pcm_substream_t *substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); struct vt1724_pcm_reg *reg = substream->runtime->private_data; spin_lock_irq(&ice->reg_lock); outl(substream->runtime->dma_addr, ice->profi_port + reg->addr); outw((snd_pcm_lib_buffer_bytes(substream) >> 2) - 1, ice->profi_port + reg->size); outw((snd_pcm_lib_period_bytes(substream) >> 2) - 1, ice->profi_port + reg->count); spin_unlock_irq(&ice->reg_lock); return 0;}static snd_pcm_uframes_t snd_vt1724_pcm_pointer(snd_pcm_substream_t *substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); struct vt1724_pcm_reg *reg = substream->runtime->private_data; size_t ptr; if (!(inl(ICEMT1724(ice, DMA_CONTROL)) & reg->start)) return 0;#if 0 /* use ADDR register */ ptr = inl(ice->profi_port + reg->addr); ptr -= substream->runtime->dma_addr; return bytes_to_frames(substream->runtime, ptr);#else /* use SIZE register */ ptr = inw(ice->profi_port + reg->size); ptr = (ptr + 1) << 2; ptr = bytes_to_frames(substream->runtime, ptr); if (! ptr) ; else if (ptr <= substream->runtime->buffer_size) ptr = substream->runtime->buffer_size - ptr; else { snd_printd("ice1724: invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->buffer_size); ptr = 0; } return ptr;#endif}static struct vt1724_pcm_reg vt1724_playback_pro_reg = { .addr = VT1724_MT_PLAYBACK_ADDR, .size = VT1724_MT_PLAYBACK_SIZE, .count = VT1724_MT_PLAYBACK_COUNT, .start = VT1724_PDMA0_START,};static struct vt1724_pcm_reg vt1724_capture_pro_reg = { .addr = VT1724_MT_CAPTURE_ADDR, .size = VT1724_MT_CAPTURE_SIZE, .count = VT1724_MT_CAPTURE_COUNT, .start = VT1724_RDMA0_START,};static snd_pcm_hardware_t snd_vt1724_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_192000, .rate_min = 8000, .rate_max = 192000, .channels_min = 2, .channels_max = 8, .buffer_bytes_max = (1UL << 21), /* 19bits dword */ .period_bytes_min = 8 * 4 * 2, /* FIXME: constraints needed */ .period_bytes_max = (1UL << 21), .periods_min = 2, .periods_max = 1024,};static snd_pcm_hardware_t snd_vt1724_spdif ={ .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_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, .rate_min = 32000, .rate_max = 48000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (1UL << 18), /* 16bits dword */ .period_bytes_min = 2 * 4 * 2, .period_bytes_max = (1UL << 18), .periods_min = 2, .periods_max = 1024,};static snd_pcm_hardware_t snd_vt1724_2ch_stereo ={ .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_192000, .rate_min = 8000, .rate_max = 192000, .channels_min = 2, .channels_max = 2, .buffer_bytes_max = (1UL << 18), /* 16bits dword */ .period_bytes_min = 2 * 4 * 2, .period_bytes_max = (1UL << 18), .periods_min = 2, .periods_max = 1024,};/* * set rate constraints */static int set_rate_constraints(ice1712_t *ice, snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime = substream->runtime; if (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S) { /* I2S */ /* VT1720 doesn't support more than 96kHz */ if ((ice->eeprom.data[ICE_EEP2_I2S] & 0x08) && !ice->vt1720) return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192); else { runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_96000; runtime->hw.rate_max = 96000; return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96); } } else if (ice->ac97) { /* ACLINK */ runtime->hw.rate_max = 48000; runtime->hw.rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_48000; return snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_48); } return 0;}/* multi-channel playback needs alignment 8x32bit regardless of the channels * actually used */#define VT1724_BUFFER_ALIGN 0x20static int snd_vt1724_playback_pro_open(snd_pcm_substream_t * substream){ snd_pcm_runtime_t *runtime = substream->runtime; ice1712_t *ice = snd_pcm_substream_chip(substream); int chs; runtime->private_data = &vt1724_playback_pro_reg; ice->playback_pro_substream = substream; runtime->hw = snd_vt1724_playback_pro; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); set_rate_constraints(ice, substream); down(&ice->open_mutex); /* calculate the currently available channels */ for (chs = 0; chs < 3; chs++) { if (ice->pcm_reserved[chs]) break; } chs = (chs + 1) * 2; runtime->hw.channels_max = chs; if (chs > 2) /* channels must be even */ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); up(&ice->open_mutex); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); return 0;}static int snd_vt1724_capture_pro_open(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; runtime->private_data = &vt1724_capture_pro_reg; ice->capture_pro_substream = substream; runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); set_rate_constraints(ice, substream); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); return 0;}static int snd_vt1724_playback_pro_close(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); if (PRO_RATE_RESET) snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); ice->playback_pro_substream = NULL; return 0;}static int snd_vt1724_capture_pro_close(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); if (PRO_RATE_RESET) snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); ice->capture_pro_substream = NULL; return 0;}static snd_pcm_ops_t snd_vt1724_playback_pro_ops = { .open = snd_vt1724_playback_pro_open, .close = snd_vt1724_playback_pro_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vt1724_pcm_hw_params, .hw_free = snd_vt1724_pcm_hw_free, .prepare = snd_vt1724_playback_pro_prepare, .trigger = snd_vt1724_pcm_trigger, .pointer = snd_vt1724_playback_pro_pointer,};static snd_pcm_ops_t snd_vt1724_capture_pro_ops = { .open = snd_vt1724_capture_pro_open, .close = snd_vt1724_capture_pro_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vt1724_pcm_hw_params, .hw_free = snd_vt1724_pcm_hw_free, .prepare = snd_vt1724_pcm_prepare, .trigger = snd_vt1724_pcm_trigger, .pointer = snd_vt1724_pcm_pointer,};static int __devinit snd_vt1724_pcm_profi(ice1712_t * ice, int device){ snd_pcm_t *pcm; int err; err = snd_pcm_new(ice->card, "ICE1724", device, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vt1724_playback_pro_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vt1724_capture_pro_ops); pcm->private_data = ice; pcm->info_flags = 0; strcpy(pcm->name, "ICE1724"); 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; return 0;}/* * SPDIF PCM */static struct vt1724_pcm_reg vt1724_playback_spdif_reg = { .addr = VT1724_MT_PDMA4_ADDR, .size = VT1724_MT_PDMA4_SIZE, .count = VT1724_MT_PDMA4_COUNT, .start = VT1724_PDMA4_START,};static struct vt1724_pcm_reg vt1724_capture_spdif_reg = { .addr = VT1724_MT_RDMA1_ADDR, .size = VT1724_MT_RDMA1_SIZE, .count = VT1724_MT_RDMA1_COUNT, .start = VT1724_RDMA1_START,};/* update spdif control bits; call with reg_lock */static void update_spdif_bits(ice1712_t *ice, unsigned int val){ unsigned char cbit, disabled; cbit = inb(ICEREG1724(ice, SPDIF_CFG)); disabled = cbit & ~VT1724_CFG_SPDIF_OUT_EN; if (cbit != disabled) outb(disabled, ICEREG1724(ice, SPDIF_CFG)); outw(val, ICEMT1724(ice, SPDIF_CTRL)); if (cbit != disabled) outb(cbit, ICEREG1724(ice, SPDIF_CFG)); outw(val, ICEMT1724(ice, SPDIF_CTRL));}/* update SPDIF control bits according to the given rate */static void update_spdif_rate(ice1712_t *ice, unsigned int rate){ unsigned int val, nval; unsigned long flags; spin_lock_irqsave(&ice->reg_lock, flags); nval = val = inw(ICEMT1724(ice, SPDIF_CTRL)); nval &= ~(7 << 12); switch (rate) { case 44100: break; case 48000: nval |= 2 << 12; break; case 32000: nval |= 3 << 12; break; } if (val != nval) update_spdif_bits(ice, nval); spin_unlock_irqrestore(&ice->reg_lock, flags);}static int snd_vt1724_playback_spdif_prepare(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); if (! ice->force_pdma4) update_spdif_rate(ice, substream->runtime->rate); return snd_vt1724_pcm_prepare(substream);}static int snd_vt1724_playback_spdif_open(snd_pcm_substream_t *substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; runtime->private_data = &vt1724_playback_spdif_reg; ice->playback_con_substream = substream; if (ice->force_pdma4) { runtime->hw = snd_vt1724_2ch_stereo; set_rate_constraints(ice, substream);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -