📄 ali5451.c
字号:
}#define ALI5451_SPDIF(xname, xindex, value) \{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex,\info: snd_ali5451_spdif_info, get: snd_ali5451_spdif_get, \put: snd_ali5451_spdif_put, private_value: value}static int snd_ali5451_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_ali5451_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ unsigned long flags; ali_t *codec = snd_magic_cast(ali_t, kcontrol->private_data, -ENXIO); unsigned int enable; enable = ucontrol->value.integer.value[0] ? 1 : 0; spin_lock_irqsave(&codec->reg_lock, flags); switch(kcontrol->private_value) { case 0: enable = (codec->spdif_mask & 0x02) ? 1 : 0; break; case 1: enable = ((codec->spdif_mask & 0x02) && (codec->spdif_mask & 0x04)) ? 1 : 0; break; case 2: enable = (codec->spdif_mask & 0x01) ? 1 : 0; break; default: break; } ucontrol->value.integer.value[0] = enable; spin_unlock_irqrestore(&codec->reg_lock, flags); return 0;}static int snd_ali5451_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol){ unsigned long flags; ali_t *codec = snd_magic_cast(ali_t, kcontrol->private_data, -ENXIO); unsigned int change = 0, enable = 0; enable = ucontrol->value.integer.value[0] ? 1 : 0; spin_lock_irqsave(&codec->reg_lock, flags); switch (kcontrol->private_value) { case 0: change = (codec->spdif_mask & 0x02) ? 1 : 0; change = change ^ enable; if (change) { if (enable) { codec->spdif_mask |= 0x02; snd_ali_enable_spdif_out(codec); } else { codec->spdif_mask &= ~(0x02); codec->spdif_mask &= ~(0x04); snd_ali_disable_spdif_out(codec); } } break; case 1: change = (codec->spdif_mask & 0x04) ? 1 : 0; change = change ^ enable; if (change && (codec->spdif_mask & 0x02)) { if (enable) { codec->spdif_mask |= 0x04; snd_ali_enable_spdif_chnout(codec); } else { codec->spdif_mask &= ~(0x04); snd_ali_disable_spdif_chnout(codec); } } break; case 2: change = (codec->spdif_mask & 0x01) ? 1 : 0; change = change ^ enable; if (change) { if (enable) { codec->spdif_mask |= 0x01; snd_ali_enable_spdif_in(codec); } else { codec->spdif_mask &= ~(0x01); snd_ali_disable_spdif_in(codec); } } break; default: break; } spin_unlock_irqrestore(&codec->reg_lock, flags); return change;}static snd_kcontrol_new_t snd_ali5451_mixer_spdif[] __devinit = { /* spdif aplayback switch */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, 0), /* spdif out to spdif channel */ ALI5451_SPDIF("IEC958 Channel Output Switch", 0, 1), /* spdif in from spdif channel */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)};static void snd_ali_mixer_free_ac97(ac97_t *ac97){ ali_t *codec = snd_magic_cast(ali_t, ac97->private_data, return); codec->ac97 = NULL;}static int __devinit snd_ali_mixer(ali_t * codec){ ac97_t ac97; int err, idx; memset(&ac97, 0, sizeof(ac97)); ac97.write = snd_ali_codec_write; ac97.read = snd_ali_codec_read; ac97.private_data = codec; ac97.private_free = snd_ali_mixer_free_ac97; if ((err = snd_ac97_mixer(codec->card, &ac97, &codec->ac97)) < 0) { snd_printk("ali mixer creating error.\n"); return err; } if (codec->revision == ALI_5451_V02) { for(idx = 0; idx < 3; idx++) { err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); if (err < 0) return err; } } return 0;}#ifdef CONFIG_PM#ifndef PCI_OLD_SUSPENDstatic int snd_ali_suspend(struct pci_dev *dev, u32 state)#elsestatic void snd_ali_suspend(struct pci_dev *dev)#endif{#ifndef PCI_OLD_SUSPEND ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);#else ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return);#endif ali_image_t *im; unsigned long flags; int i, j; im = chip->image; if (! im)#ifndef PCI_OLD_SUSPEND return -ENXIO;#else return;#endif save_flags(flags); cli(); im->regs[ALI_MISCINT >> 2] = inl(ALI_REG(chip, ALI_MISCINT)); // im->regs[ALI_START >> 2] = inl(ALI_REG(chip, ALI_START)); im->regs[ALI_STOP >> 2] = inl(ALI_REG(chip, ALI_STOP)); // disable all IRQ bits outl(0, ALI_REG(chip, ALI_MISCINT)); for (i = 0; i < ALI_GLOBAL_REGS; i++) { if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP)) continue; im->regs[i] = inl(ALI_REG(chip, i*4)); } for (i = 0; i < ALI_CHANNELS; i++) { outb(i, ALI_REG(chip, ALI_GC_CIR)); for (j = 0; j < ALI_CHANNEL_REGS; j++) im->channel_regs[i][j] = inl(ALI_REG(chip, j*4 + 0xe0)); } // stop all HW channel outl(0xffffffff, ALI_REG(chip, ALI_STOP)); restore_flags(flags);#ifndef PCI_OLD_SUSPEND return 0;#endif}#ifndef PCI_OLD_SUSPENDstatic int snd_ali_resume(struct pci_dev *dev)#elsestatic void snd_ali_resume(struct pci_dev *dev)#endif{#ifndef PCI_OLD_SUSPEND ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return -ENXIO);#else ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(dev), return);#endif ali_image_t *im; unsigned long flags; int i, j; im = chip->image; if (! im)#ifndef PCI_OLD_SUSPEND return -ENXIO;#else return;#endif pci_enable_device(chip->pci); save_flags(flags); cli(); for (i = 0; i < ALI_CHANNELS; i++) { outb(i, ALI_REG(chip, ALI_GC_CIR)); for (j = 0; j < ALI_CHANNEL_REGS; j++) outl(im->channel_regs[i][j], ALI_REG(chip, j*4 + 0xe0)); } for (i = 0; i < ALI_GLOBAL_REGS; i++) { if ((i*4 == ALI_MISCINT) || (i*4 == ALI_STOP) || (i*4 == ALI_START)) continue; outl(im->regs[i], ALI_REG(chip, i*4)); } snd_ac97_resume(chip->ac97); // start HW channel outl(im->regs[ALI_START >> 2], ALI_REG(chip, ALI_START)); // restore IRQ enable bits outl(im->regs[ALI_MISCINT >> 2], ALI_REG(chip, ALI_MISCINT)); restore_flags(flags);#ifndef PCI_OLD_SUSPEND return 0;#endif}#endifstatic int snd_ali_free(ali_t * codec){ snd_ali_disable_address_interrupt(codec); synchronize_irq(); if (codec->irq >=0) free_irq(codec->irq, (void *)codec); if (codec->res_port) { release_resource(codec->res_port); kfree_nocheck(codec->res_port); }#ifdef CONFIG_PM if (codec->image) kfree(codec->image);#endif snd_magic_kfree(codec); return 0;}static int snd_ali_chip_init(ali_t *codec){ unsigned int legacy; unsigned char temp; struct pci_dev *pci_dev = NULL; snd_ali_printk("chip initializing ... \n"); if (snd_ali_reset_5451(codec)) { snd_printk("ali_chip_init: reset 5451 error.\n"); return -1; } if (codec->revision == ALI_5451_V02) { pci_dev = codec->pci_m1533; if (pci_dev == NULL) return -1; pci_read_config_byte(pci_dev, 0x59, &temp); pci_dev = pci_find_device(0x10b9,0x7101, pci_dev); if (pci_dev == NULL) return -1; pci_read_config_byte(pci_dev,0xb8,&temp); temp |= 1 << 6; pci_write_config_byte(pci_dev, 0xB8, temp); } pci_read_config_dword(codec->pci, 0x44, &legacy); legacy &= 0xff00ff00; legacy |= 0x000800aa; pci_write_config_dword(codec->pci, 0x44, legacy); outl(0x80000001, ALI_REG(codec, ALI_GLOBAL_CONTROL)); outl(0x00000000, ALI_REG(codec, ALI_AINTEN)); outl(0xffffffff, ALI_REG(codec, ALI_AINT)); outl(0x00000000, ALI_REG(codec, ALI_VOLUME)); outb(0x10, ALI_REG(codec, ALI_MPUR2)); codec->ac97_ext_id = snd_ali_codec_peek(codec, 0, AC97_EXTENDED_ID); codec->ac97_ext_status = snd_ali_codec_peek(codec, 0, AC97_EXTENDED_STATUS); if (codec->revision == ALI_5451_V02) { snd_ali_enable_spdif_out(codec); codec->spdif_mask = 0x00000002; } snd_ali_printk("chip initialize succeed.\n"); return 0;}static int __devinit snd_ali_resources(ali_t *codec){ snd_ali_printk("resouces allocation ...\n"); if ((codec->res_port = request_region(codec->port, 0x100, "ALI 5451")) == NULL) { snd_ali_free(codec); snd_printk("Unalbe to request io ports.\n"); return -EBUSY; } if (request_irq(codec->pci->irq, snd_ali_card_interrupt, SA_INTERRUPT|SA_SHIRQ, "ALI 5451", (void *)codec)) { snd_ali_free(codec); snd_printk("Unable to request irq.\n"); return -EBUSY; } codec->irq = codec->pci->irq; snd_ali_printk("resouces allocated.\n"); return 0;}static int snd_ali_dev_free(snd_device_t *device) { ali_t *codec=snd_magic_cast(ali_t, device->device_data, return -ENXIO); snd_ali_free(codec); return 0;}static int __devinit snd_ali_create(snd_card_t * card, struct pci_dev *pci, int pcm_streams, ali_t ** r_ali){ ali_t *codec; int i, err; unsigned short cmdw = 0; struct pci_dev *pci_dev = NULL; static snd_device_ops_t ops = { (snd_dev_free_t *)snd_ali_dev_free, NULL, NULL }; *r_ali = NULL; snd_ali_printk("creating ...\n"); /* enable PCI device */ if ((err = pci_enable_device(pci)) < 0) return err; /* check, if we can restrict PCI DMA transfers to 30 bits */ if (!pci_dma_supported(pci, 0x3fffffff)) { snd_printk("architecture does not support 30bit PCI busmaster DMA\n"); return -ENXIO; } pci_set_dma_mask(pci, 0x3fffffff); if ((codec = snd_magic_kcalloc(ali_t, 0, GFP_KERNEL)) == NULL) return -ENOMEM; spin_lock_init(&codec->reg_lock); spin_lock_init(&codec->voice_alloc); codec->card = card; codec->pci = pci; codec->irq = -1; codec->port = pci_resource_start(pci, 0); pci_read_config_byte(pci, PCI_REVISION_ID, &codec->revision); if (pcm_streams < 1) pcm_streams = 1; if (pcm_streams > 32) pcm_streams = 32; pci_set_master(pci); pci_read_config_word(pci, PCI_COMMAND, &cmdw); if ((cmdw & PCI_COMMAND_IO) != PCI_COMMAND_IO) { cmdw |= PCI_COMMAND_IO; pci_write_config_word(pci, PCI_COMMAND, cmdw); } pci_set_master(pci); if (snd_ali_resources(codec)) { return -EBUSY; } synchronize_irq(); codec->synth.chmap = 0; codec->synth.chcnt = 0; codec->spdif_mask = 0; codec->synth.synthcount = 0; if (codec->revision == ALI_5451_V02) codec->chregs.regs.ac97read = ALI_AC97_WRITE; else codec->chregs.regs.ac97read = ALI_AC97_READ; codec->chregs.regs.ac97write = ALI_AC97_WRITE; codec->chregs.regs.start = ALI_START; codec->chregs.regs.stop = ALI_STOP; codec->chregs.regs.aint = ALI_AINT; codec->chregs.regs.ainten = ALI_AINTEN; codec->chregs.data.start = 0x00; codec->chregs.data.stop = 0x00; codec->chregs.data.aint = 0x00; codec->chregs.data.ainten = 0x00; pci_dev = pci_find_device(0x10b9,0x1533, pci_dev); codec->pci_m1533 = pci_dev; pci_dev = pci_find_device(0x10b9,0x7101, pci_dev); codec->pci_m7101 = pci_dev; snd_ali_printk("snd_device_new is called.\n"); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops)) < 0) { snd_ali_free(codec); return err; } /* initialise synth voices*/ for (i = 0; i < ALI_CHANNELS; i++ ) { codec->synth.voices[i].number = i; } if ((err = snd_ali_chip_init(codec)) < 0) { snd_printk("ali create: chip init error.\n"); snd_ali_free(codec); return err; }#ifdef CONFIG_PM codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL); if (! codec->image) snd_printk("can't allocate apm buffer\n");#endif snd_ali_enable_address_interrupt(codec); *r_ali = codec; snd_ali_printk("created.\n"); return 0;}static int __devinit snd_ali_probe(struct pci_dev *pci, const struct pci_device_id *id){ static int dev; snd_card_t *card; ali_t *codec; int err; snd_ali_printk("probe ...\n"); if (dev >= SNDRV_CARDS) return -ENODEV; if (!snd_enable[dev]) { dev++; return -ENOENT; } card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; if ((err = snd_ali_create(card, pci, snd_pcm_channels[dev], &codec)) < 0) { snd_card_free(card); return err; } snd_ali_printk("mixer building ...\n"); if ((err = snd_ali_mixer(codec)) < 0) { snd_card_free(card); return err; } snd_ali_printk("pcm building ...\n"); if ((err = snd_ali_pcm(codec, 0, NULL)) < 0) { snd_card_free(card); return err; } strcpy(card->driver, "ALI5451"); strcpy(card->shortname, "ALI 5451"); sprintf(card->longname, "%s at 0x%lx, irq %li", card->shortname, codec->port, codec->irq); snd_ali_printk("register card.\n"); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, codec); dev++; return 0;}static void __devexit snd_ali_remove(struct pci_dev *pci){ ali_t *chip = snd_magic_cast(ali_t, pci_get_drvdata(pci), return); if (chip) snd_card_free(chip->card); pci_set_drvdata(pci, NULL);}static struct pci_driver driver = { name: "ALI 5451", id_table: snd_ali_ids, probe: snd_ali_probe, remove: __devexit_p(snd_ali_remove),#ifdef CONFIG_PM suspend: snd_ali_suspend, resume: snd_ali_resume,#endif}; static int __init alsa_card_ali_init(void){ int err; if ((err = pci_module_init(&driver)) < 0) {#ifdef MODULE printk(KERN_ERR "ALi pci audio not found or device busy.\n");#endif return err; } return 0;}static void __exit alsa_card_ali_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_ali_init)module_exit(alsa_card_ali_exit)#ifndef MODULE/* format is: snd-ali5451=snd_enable,snd_index,snd_id,snd_pcm_channels */static int __init alsa_card_ali_setup(char *str){ static unsigned __initdata nr_dev = 0; if (nr_dev >= SNDRV_CARDS) return 0; (void)(get_option(&str,&snd_enable[nr_dev]) == 2 && get_option(&str,&snd_index[nr_dev]) == 2 && get_id(&str,&snd_id[nr_dev]) == 2 && get_option(&str,&snd_pcm_channels[nr_dev]) == 2); nr_dev++; return 1;}__setup("snd-ali5451=", alsa_card_ali_setup);#endif /* ifndef */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -