📄 ice1724.c
字号:
} else runtime->hw = snd_vt1724_spdif; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 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_spdif_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_con_substream = NULL; return 0;}static int snd_vt1724_capture_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_capture_spdif_reg; ice->capture_con_substream = substream; if (ice->force_rdma1) { runtime->hw = snd_vt1724_2ch_stereo; set_rate_constraints(ice, substream); } else runtime->hw = snd_vt1724_spdif; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); 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_spdif_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_con_substream = NULL; return 0;}static snd_pcm_ops_t snd_vt1724_playback_spdif_ops = { .open = snd_vt1724_playback_spdif_open, .close = snd_vt1724_playback_spdif_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vt1724_pcm_hw_params, .hw_free = snd_vt1724_pcm_hw_free, .prepare = snd_vt1724_playback_spdif_prepare, .trigger = snd_vt1724_pcm_trigger, .pointer = snd_vt1724_pcm_pointer,};static snd_pcm_ops_t snd_vt1724_capture_spdif_ops = { .open = snd_vt1724_capture_spdif_open, .close = snd_vt1724_capture_spdif_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_spdif(ice1712_t * ice, int device){ char *name; snd_pcm_t *pcm; int play, capt; int err; if (ice->force_pdma4 || (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_OUT_INT)) { play = 1; ice->has_spdif = 1; } else play = 0; if (ice->force_rdma1 || (ice->eeprom.data[ICE_EEP2_SPDIF] & VT1724_CFG_SPDIF_IN)) { capt = 1; ice->has_spdif = 1; } else capt = 0; if (! play && ! capt) return 0; /* no spdif device */ if (ice->force_pdma4 || ice->force_rdma1) name = "ICE1724 Secondary"; else name = "IEC1724 IEC958"; err = snd_pcm_new(ice->card, name, device, play, capt, &pcm); if (err < 0) return err; if (play) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vt1724_playback_spdif_ops); if (capt) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_vt1724_capture_spdif_ops); pcm->private_data = ice; pcm->info_flags = 0; strcpy(pcm->name, name); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 64*1024); ice->pcm = pcm; return 0;}/* * independent surround PCMs */static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { { .addr = VT1724_MT_PDMA1_ADDR, .size = VT1724_MT_PDMA1_SIZE, .count = VT1724_MT_PDMA1_COUNT, .start = VT1724_PDMA1_START, }, { .addr = VT1724_MT_PDMA2_ADDR, .size = VT1724_MT_PDMA2_SIZE, .count = VT1724_MT_PDMA2_COUNT, .start = VT1724_PDMA2_START, }, { .addr = VT1724_MT_PDMA3_ADDR, .size = VT1724_MT_PDMA3_SIZE, .count = VT1724_MT_PDMA3_COUNT, .start = VT1724_PDMA3_START, },};static int snd_vt1724_playback_indep_prepare(snd_pcm_substream_t * substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); unsigned char val; spin_lock_irq(&ice->reg_lock); val = 3 - substream->number; if (inb(ICEMT1724(ice, BURST)) < val) outb(val, ICEMT1724(ice, BURST)); spin_unlock_irq(&ice->reg_lock); return snd_vt1724_pcm_prepare(substream);}static int snd_vt1724_playback_indep_open(snd_pcm_substream_t *substream){ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; down(&ice->open_mutex); /* already used by PDMA0? */ if (ice->pcm_reserved[substream->number]) { up(&ice->open_mutex); return -EBUSY; /* FIXME: should handle blocking mode properly */ } up(&ice->open_mutex); runtime->private_data = &vt1724_playback_dma_regs[substream->number]; ice->playback_con_substream_ds[substream->number] = 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); return 0;}static int snd_vt1724_playback_indep_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_con_substream_ds[substream->number] = NULL; ice->pcm_reserved[substream->number] = NULL; return 0;}static snd_pcm_ops_t snd_vt1724_playback_indep_ops = { .open = snd_vt1724_playback_indep_open, .close = snd_vt1724_playback_indep_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_vt1724_pcm_hw_params, .hw_free = snd_vt1724_pcm_hw_free, .prepare = snd_vt1724_playback_indep_prepare, .trigger = snd_vt1724_pcm_trigger, .pointer = snd_vt1724_pcm_pointer,};static int __devinit snd_vt1724_pcm_indep(ice1712_t * ice, int device){ snd_pcm_t *pcm; int play; int err; play = ice->num_total_dacs / 2 - 1; if (play <= 0) return 0; err = snd_pcm_new(ice->card, "ICE1724 Surrounds", device, play, 0, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_vt1724_playback_indep_ops); pcm->private_data = ice; pcm->info_flags = 0; strcpy(pcm->name, "ICE1724 Surround PCM"); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(ice->pci), 64*1024, 64*1024); ice->pcm_ds = pcm; return 0;}/* * Mixer section */static int __devinit snd_vt1724_ac97_mixer(ice1712_t * ice){ int err; if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) { ac97_bus_t *pbus; ac97_template_t ac97; static ac97_bus_ops_t ops = { .write = snd_vt1724_ac97_write, .read = snd_vt1724_ac97_read, }; /* cold reset */ outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); mdelay(5); /* FIXME */ outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); if ((err = snd_ac97_bus(ice->card, 0, &ops, NULL, &pbus)) < 0) return err; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = ice; if ((err = snd_ac97_mixer(pbus, &ac97, &ice->ac97)) < 0) printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); else return 0; } /* I2S mixer only */ strcat(ice->card->mixername, "ICE1724 - multitrack"); return 0;}/* * */static inline unsigned int eeprom_triple(ice1712_t *ice, int idx){ return (unsigned int)ice->eeprom.data[idx] | \ ((unsigned int)ice->eeprom.data[idx + 1] << 8) | \ ((unsigned int)ice->eeprom.data[idx + 2] << 16);}static void snd_vt1724_proc_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ ice1712_t *ice = entry->private_data; unsigned int idx; snd_iprintf(buffer, "%s\n\n", ice->card->longname); snd_iprintf(buffer, "EEPROM:\n"); snd_iprintf(buffer, " Subvendor : 0x%x\n", ice->eeprom.subvendor); snd_iprintf(buffer, " Size : %i bytes\n", ice->eeprom.size); snd_iprintf(buffer, " Version : %i\n", ice->eeprom.version); snd_iprintf(buffer, " System Config : 0x%x\n", ice->eeprom.data[ICE_EEP2_SYSCONF]); snd_iprintf(buffer, " ACLink : 0x%x\n", ice->eeprom.data[ICE_EEP2_ACLINK]); snd_iprintf(buffer, " I2S : 0x%x\n", ice->eeprom.data[ICE_EEP2_I2S]); snd_iprintf(buffer, " S/PDIF : 0x%x\n", ice->eeprom.data[ICE_EEP2_SPDIF]); snd_iprintf(buffer, " GPIO direction : 0x%x\n", ice->eeprom.gpiodir); snd_iprintf(buffer, " GPIO mask : 0x%x\n", ice->eeprom.gpiomask); snd_iprintf(buffer, " GPIO state : 0x%x\n", ice->eeprom.gpiostate); for (idx = 0x12; idx < ice->eeprom.size; idx++) snd_iprintf(buffer, " Extra #%02i : 0x%x\n", idx, ice->eeprom.data[idx]); snd_iprintf(buffer, "\nRegisters:\n"); snd_iprintf(buffer, " PSDOUT03 : 0x%08x\n", (unsigned)inl(ICEMT1724(ice, ROUTE_PLAYBACK))); for (idx = 0x0; idx < 0x20 ; idx++) snd_iprintf(buffer, " CCS%02x : 0x%02x\n", idx, inb(ice->port+idx)); for (idx = 0x0; idx < 0x30 ; idx++) snd_iprintf(buffer, " MT%02x : 0x%02x\n", idx, inb(ice->profi_port+idx));}static void __devinit snd_vt1724_proc_init(ice1712_t * ice){ snd_info_entry_t *entry; if (! snd_card_proc_new(ice->card, "ice1724", &entry)) snd_info_set_text_ops(entry, ice, 1024, snd_vt1724_proc_read);}/* * */static int snd_vt1724_eeprom_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = sizeof(ice1712_eeprom_t); return 0;}static int snd_vt1724_eeprom_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ice1712_t *ice = snd_kcontrol_chip(kcontrol); memcpy(ucontrol->value.bytes.data, &ice->eeprom, sizeof(ice->eeprom)); return 0;}static snd_kcontrol_new_t snd_vt1724_eeprom __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1724 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, .info = snd_vt1724_eeprom_info, .get = snd_vt1724_eeprom_get};/* */static int snd_vt1724_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; uinfo->count = 1; return 0;}static unsigned int encode_spdif_bits(snd_aes_iec958_t *diga){ unsigned int val; val = diga->status[0] & 0x03; /* professional, non-audio */ if (val & 0x01) { /* professional */ if ((diga->status[0] & IEC958_AES0_PRO_EMPHASIS) == IEC958_AES0_PRO_EMPHASIS_5015) val |= 1U << 3; switch (diga->status[0] & IEC958_AES0_PRO_FS) { case IEC958_AES0_PRO_FS_44100: break; case IEC958_AES0_PRO_FS_32000: val |= 3U << 12; break; default: val |= 2U << 12; break; } } else { /* consumer */ val |= diga->status[1] & 0x04; /* copyright */ if ((diga->status[0] & IEC958_AES0_CON_EMPHASIS)== IEC958_AES0_CON_EMPHASIS_5015) val |= 1U << 3; val |= (unsigned int)(diga->status[1] & 0x3f) << 4; /* category */ val |= (unsigned int)(diga->status[3] & IEC958_AES3_CON_FS) << 12; /* fs */ } return val;}static void decode_spdif_bits(snd_aes_iec958_t *diga, unsigned int val){ memset(diga->status, 0, sizeof(diga->status)); diga->status[0] = val & 0x03; /* professional, non-audio */ if (val & 0x01) { /* professional */ if (val & (1U << 3)) diga->status[0] |= IEC958_AES0_PRO_EMPHASIS_5015; switch ((val >> 12) & 0x7) { case 0: break; case 2: diga->status[0] |= IEC958_AES0_PRO_FS_32000; break; default: diga->status[0] |= IEC958_AES0_PRO_FS_48000; break; } } else { /* consumer */ diga->status[0] |= val & (1U << 2); /* copyright */ if (val & (1U << 3)) diga->status[0] |= IEC958_AES0_CON_EMPHASIS_5015; diga->status[1] |= (val >> 4) & 0x3f; /* category */ diga->status[3] |= (val >> 12) & 0x07; /* fs */ }}static int snd_vt1724_spdif_default_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ice1712_t *ice = snd_kcontrol_chip(kcontrol); unsigned int val; val = inw(ICEMT1724(ice, SPDIF_CTRL)); decode_spdif_bits(&ucontrol->value.iec958, val); return 0;}static int snd_vt1724_spdif_default_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ice1712_t *ice = snd_kcontrol_chip(kcontrol); unsigned int val, old; val = encode_spdif_bits(&ucontrol->value.iec958); spin_lock_irq(&ice->reg_lock); old = inw(ICEMT1724(ice, SPDIF_CTRL)); if (val != old) update_spdif_bits(ice, val); spin_unlock_irq(&ice->reg_lock); return (val != old);}static snd_kcontrol_new_t snd_vt1724_spdif_default __devinitdata ={ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .info = snd_vt1724_spdif_info, .get = snd_vt1724_spdif_default_get, .put = snd_vt1724_spdif_default_put};static int snd_vt1724_spdif_maskc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO | IEC958_AES0_PROFESSIONAL | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS; ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_CATEGORY; ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -