📄 emu10k1x.c
字号:
if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { if (chip->midi.interrupt) chip->midi.interrupt(chip, status); else snd_emu10k1x_intr_disable(chip, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); } // acknowledge the interrupt if necessary if(status) outl(status, chip->port+IPR);// snd_printk(KERN_INFO "interrupt %08x\n", status); } return IRQ_HANDLED;}static void snd_emu10k1x_pcm_free(snd_pcm_t *pcm){ emu10k1x_t *emu = pcm->private_data; emu->pcm = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}static int __devinit snd_emu10k1x_pcm(emu10k1x_t *emu, int device, snd_pcm_t **rpcm){ snd_pcm_t *pcm; int err; int capture = 0; if (rpcm) *rpcm = NULL; if (device == 0) capture = 1; if ((err = snd_pcm_new(emu->card, "emu10k1x", device, 1, capture, &pcm)) < 0) return err; pcm->private_data = emu; pcm->private_free = snd_emu10k1x_pcm_free; switch(device) { case 0: snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_emu10k1x_capture_ops); break; case 1: case 2: snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1x_playback_ops); break; } pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; switch(device) { case 0: strcpy(pcm->name, "EMU10K1X Front"); break; case 1: strcpy(pcm->name, "EMU10K1X Rear"); break; case 2: strcpy(pcm->name, "EMU10K1X Center/LFE"); break; } emu->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 32*1024, 32*1024); if (rpcm) *rpcm = pcm; return 0;}static int __devinit snd_emu10k1x_create(snd_card_t *card, struct pci_dev *pci, emu10k1x_t **rchip){ emu10k1x_t *chip; int err; int ch; static snd_device_ops_t ops = { .dev_free = snd_emu10k1x_dev_free, }; *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; if (pci_set_dma_mask(pci, 0x0fffffff) < 0 || pci_set_consistent_dma_mask(pci, 0x0fffffff) < 0) { snd_printk(KERN_ERR "error to set 28bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } chip->card = card; chip->pci = pci; chip->irq = -1; spin_lock_init(&chip->emu_lock); spin_lock_init(&chip->voice_lock); chip->port = pci_resource_start(pci, 0); if ((chip->res_port = request_region(chip->port, 8, "EMU10K1X")) == NULL) { snd_printk(KERN_ERR "emu10k1x: cannot allocate the port 0x%lx\n", chip->port); snd_emu10k1x_free(chip); return -EBUSY; } if (request_irq(pci->irq, snd_emu10k1x_interrupt, SA_INTERRUPT|SA_SHIRQ, "EMU10K1X", (void *)chip)) { snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq); snd_emu10k1x_free(chip); return -EBUSY; } chip->irq = pci->irq; if(snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 4 * 1024, &chip->dma_buffer) < 0) { snd_emu10k1x_free(chip); return -ENOMEM; } pci_set_master(pci); /* read revision & serial */ pci_read_config_byte(pci, PCI_REVISION_ID, (char *)&chip->revision); pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, chip->revision, chip->serial); outl(0, chip->port + INTE); for(ch = 0; ch < 3; ch++) { chip->voices[ch].emu = chip; chip->voices[ch].number = ch; } /* * Init to 0x02109204 : * Clock accuracy = 0 (1000ppm) * Sample Rate = 2 (48kHz) * Audio Channel = 1 (Left of 2) * Source Number = 0 (Unspecified) * Generation Status = 1 (Original for Cat Code 12) * Cat Code = 12 (Digital Signal Mixer) * Mode = 0 (Mode 0) * Emphasis = 0 (None) * CP = 1 (Copyright unasserted) * AN = 0 (Audio data) * P = 0 (Consumer) */ snd_emu10k1x_ptr_write(chip, SPCS0, 0, chip->spdif_bits[0] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_emu10k1x_ptr_write(chip, SPCS1, 0, chip->spdif_bits[1] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_emu10k1x_ptr_write(chip, SPCS2, 0, chip->spdif_bits[2] = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 | SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | 0x00000000 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT); snd_emu10k1x_ptr_write(chip, SPDIF_SELECT, 0, 0x700); // disable SPDIF snd_emu10k1x_ptr_write(chip, ROUTING, 0, 0x1003F); // routing snd_emu10k1x_gpio_write(chip, 0x1080); // analog mode outl(HCFG_LOCKSOUNDCACHE|HCFG_AUDIOENABLE, chip->port+HCFG); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_emu10k1x_free(chip); return err; } *rchip = chip; return 0;}static void snd_emu10k1x_proc_reg_read(snd_info_entry_t *entry, snd_info_buffer_t * buffer){ emu10k1x_t *emu = entry->private_data; unsigned long value,value1,value2; unsigned long flags; int i; snd_iprintf(buffer, "Registers:\n\n"); for(i = 0; i < 0x20; i+=4) { spin_lock_irqsave(&emu->emu_lock, flags); value = inl(emu->port + i); spin_unlock_irqrestore(&emu->emu_lock, flags); snd_iprintf(buffer, "Register %02X: %08lX\n", i, value); } snd_iprintf(buffer, "\nRegisters\n\n"); for(i = 0; i <= 0x48; i++) { value = snd_emu10k1x_ptr_read(emu, i, 0); if(i < 0x10 || (i >= 0x20 && i < 0x40)) { value1 = snd_emu10k1x_ptr_read(emu, i, 1); value2 = snd_emu10k1x_ptr_read(emu, i, 2); snd_iprintf(buffer, "%02X: %08lX %08lX %08lX\n", i, value, value1, value2); } else { snd_iprintf(buffer, "%02X: %08lX\n", i, value); } }}static void snd_emu10k1x_proc_reg_write(snd_info_entry_t *entry, snd_info_buffer_t *buffer){ emu10k1x_t *emu = entry->private_data; char line[64]; unsigned int reg, channel_id , val; while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; if ((reg < 0x49) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 2) ) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); }}static int __devinit snd_emu10k1x_proc_init(emu10k1x_t * emu){ snd_info_entry_t *entry; if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { snd_info_set_text_ops(entry, emu, 1024, snd_emu10k1x_proc_reg_read); entry->c.text.write_size = 64; entry->c.text.write = snd_emu10k1x_proc_reg_write; entry->mode |= S_IWUSR; entry->private_data = emu; } return 0;}static int snd_emu10k1x_shared_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo){ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; return 0;}static int snd_emu10k1x_shared_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); ucontrol->value.integer.value[0] = (snd_emu10k1x_ptr_read(emu, SPDIF_SELECT, 0) == 0x700) ? 0 : 1; return 0;}static int snd_emu10k1x_shared_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); unsigned int val; int change = 0; val = ucontrol->value.integer.value[0] ; if (val) { // enable spdif output snd_emu10k1x_ptr_write(emu, SPDIF_SELECT, 0, 0x000); snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x700); snd_emu10k1x_gpio_write(emu, 0x1000); } else { // disable spdif output snd_emu10k1x_ptr_write(emu, SPDIF_SELECT, 0, 0x700); snd_emu10k1x_ptr_write(emu, ROUTING, 0, 0x1003F); snd_emu10k1x_gpio_write(emu, 0x1080); } return change;}static snd_kcontrol_new_t snd_emu10k1x_shared_spdif __devinitdata ={ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog/Digital Output Jack", .info = snd_emu10k1x_shared_spdif_info, .get = snd_emu10k1x_shared_spdif_get, .put = snd_emu10k1x_shared_spdif_put};static int snd_emu10k1x_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 int snd_emu10k1x_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; return 0;}static int snd_emu10k1x_spdif_get_mask(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ ucontrol->value.iec958.status[0] = 0xff; ucontrol->value.iec958.status[1] = 0xff; ucontrol->value.iec958.status[2] = 0xff; ucontrol->value.iec958.status[3] = 0xff; return 0;}static int snd_emu10k1x_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ emu10k1x_t *emu = snd_kcontrol_chip(kcontrol); unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); int change; unsigned int val; val = (ucontrol->value.iec958.status[0] << 0) | (ucontrol->value.iec958.status[1] << 8) | (ucontrol->value.iec958.status[2] << 16) | (ucontrol->value.iec958.status[3] << 24); change = val != emu->spdif_bits[idx]; if (change) { snd_emu10k1x_ptr_write(emu, SPCS0 + idx, 0, val); emu->spdif_bits[idx] = val; } return change;}static snd_kcontrol_new_t snd_emu10k1x_spdif_mask_control ={ .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), .count = 3, .info = snd_emu10k1x_spdif_info, .get = snd_emu10k1x_spdif_get_mask};static snd_kcontrol_new_t snd_emu10k1x_spdif_control ={ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), .count = 3, .info = snd_emu10k1x_spdif_info, .get = snd_emu10k1x_spdif_get, .put = snd_emu10k1x_spdif_put};static int __devinit snd_emu10k1x_mixer(emu10k1x_t *emu){ int err; snd_kcontrol_t *kctl; snd_card_t *card = emu->card; if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_mask_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; if ((kctl = snd_ctl_new1(&snd_emu10k1x_shared_spdif, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; if ((kctl = snd_ctl_new1(&snd_emu10k1x_spdif_control, emu)) == NULL) return -ENOMEM; if ((err = snd_ctl_add(card, kctl))) return err; return 0;}#define EMU10K1X_MIDI_MODE_INPUT (1<<0)#define EMU10K1X_MIDI_MODE_OUTPUT (1<<1)static inline unsigned char mpu401_read(emu10k1x_t *emu, emu10k1x_midi_t *mpu, int idx){ return (unsigned char)snd_emu10k1x_ptr_read(emu, mpu->port + idx, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -