📄 ali5451.c
字号:
static int __devinit snd_ali_build_pcms(struct snd_ali *codec){ int i, err; for (i = 0; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms); i++) { err = snd_ali_pcm(codec, i, &ali_pcms[i]); if (err < 0) return err; } return 0;}#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}#define snd_ali5451_spdif_info snd_ctl_boolean_mono_infostatic int snd_ali5451_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_ali *codec = kcontrol->private_data; unsigned int enable; enable = ucontrol->value.integer.value[0] ? 1 : 0; spin_lock_irq(&codec->reg_lock); 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_irq(&codec->reg_lock); return 0;}static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol){ struct snd_ali *codec = kcontrol->private_data; unsigned int change = 0, enable = 0; enable = ucontrol->value.integer.value[0] ? 1 : 0; spin_lock_irq(&codec->reg_lock); 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_irq(&codec->reg_lock); return change;}static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = { /* spdif aplayback switch */ /* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0), /* spdif out to spdif channel */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Channel Output ",NONE,SWITCH), 0, 1), /* spdif in from spdif channel */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2)};static int __devinit snd_ali_mixer(struct snd_ali * codec){ struct snd_ac97_template ac97; unsigned int idx; int i, err; static struct snd_ac97_bus_ops ops = { .write = snd_ali_codec_write, .read = snd_ali_codec_read, }; err = snd_ac97_bus(codec->card, 0, &ops, codec, &codec->ac97_bus); if (err < 0) return err; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = codec; for (i = 0; i < codec->num_of_codecs; i++) { ac97.num = i; err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i]); if (err < 0) { snd_printk(KERN_ERR "ali mixer %d creating error.\n", i); if (i == 0) return err; codec->num_of_codecs = 1; break; } } if (codec->spdif_support) { for (idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); 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_PMstatic int ali_suspend(struct pci_dev *pci, pm_message_t state){ struct snd_card *card = pci_get_drvdata(pci); struct snd_ali *chip = card->private_data; struct snd_ali_image *im; int i, j; im = chip->image; if (!im) return 0; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->num_of_codecs; i++) { snd_pcm_suspend_all(chip->pcm[i]); snd_ac97_suspend(chip->ac97[i]); } spin_lock_irq(&chip->reg_lock); 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)); spin_unlock_irq(&chip->reg_lock); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0;}static int ali_resume(struct pci_dev *pci){ struct snd_card *card = pci_get_drvdata(pci); struct snd_ali *chip = card->private_data; struct snd_ali_image *im; int i, j; im = chip->image; if (!im) return 0; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "ali5451: pci_enable_device failed, " "disabling device\n"); snd_card_disconnect(card); return -EIO; } pci_set_master(pci); spin_lock_irq(&chip->reg_lock); 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)); } /* 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)); spin_unlock_irq(&chip->reg_lock); for (i = 0 ; i < chip->num_of_codecs; i++) snd_ac97_resume(chip->ac97[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0;}#endif /* CONFIG_PM */static int snd_ali_free(struct snd_ali * codec){ if (codec->hw_initialized) snd_ali_disable_address_interrupt(codec); if (codec->irq >= 0) { synchronize_irq(codec->irq); free_irq(codec->irq, codec); } if (codec->port) pci_release_regions(codec->pci); pci_disable_device(codec->pci);#ifdef CONFIG_PM kfree(codec->image);#endif pci_dev_put(codec->pci_m1533); pci_dev_put(codec->pci_m7101); kfree(codec); return 0;}static int snd_ali_chip_init(struct snd_ali *codec){ unsigned int legacy; unsigned char temp; struct pci_dev *pci_dev; snd_ali_printk("chip initializing ... \n"); if (snd_ali_reset_5451(codec)) { snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.\n"); return -1; } if (codec->revision == ALI_5451_V02) { pci_dev = codec->pci_m1533; pci_read_config_byte(pci_dev, 0x59, &temp); temp |= 0x80; pci_write_config_byte(pci_dev, 0x59, temp); pci_dev = codec->pci_m7101; pci_read_config_byte(pci_dev, 0xb8, &temp); temp |= 0x20; 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->spdif_support) { snd_ali_enable_spdif_out(codec); codec->spdif_mask = 0x00000002; } codec->num_of_codecs = 1; /* secondary codec - modem */ if (inl(ALI_REG(codec, ALI_SCTRL)) & ALI_SCTRL_CODEC2_READY) { codec->num_of_codecs++; outl(inl(ALI_REG(codec, ALI_SCTRL)) | (ALI_SCTRL_LINE_IN2 | ALI_SCTRL_GPIO_IN2 | ALI_SCTRL_LINE_OUT_EN), ALI_REG(codec, ALI_SCTRL)); } snd_ali_printk("chip initialize succeed.\n"); return 0;}/* proc for register dump */static void snd_ali_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buf){ struct snd_ali *codec = entry->private_data; int i; for (i = 0; i < 256 ; i+= 4) snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i)));}static void __devinit snd_ali_proc_init(struct snd_ali *codec){ struct snd_info_entry *entry; if (!snd_card_proc_new(codec->card, "ali5451", &entry)) snd_info_set_text_ops(entry, codec, snd_ali_proc_read);}static int __devinit snd_ali_resources(struct snd_ali *codec){ int err; snd_ali_printk("resouces allocation ...\n"); err = pci_request_regions(codec->pci, "ALI 5451"); if (err < 0) return err; codec->port = pci_resource_start(codec->pci, 0); if (request_irq(codec->pci->irq, snd_ali_card_interrupt, IRQF_SHARED, "ALI 5451", codec)) { snd_printk(KERN_ERR "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(struct snd_device *device){ struct snd_ali *codec = device->device_data; snd_ali_free(codec); return 0;}static int __devinit snd_ali_create(struct snd_card *card, struct pci_dev *pci, int pcm_streams, int spdif_support, struct snd_ali ** r_ali){ struct snd_ali *codec; int i, err; unsigned short cmdw; static struct snd_device_ops ops = { .dev_free = snd_ali_dev_free, }; *r_ali = NULL; snd_ali_printk("creating ...\n"); /* enable PCI device */ err = pci_enable_device(pci); if (err < 0) return err; /* check, if we can restrict PCI DMA transfers to 31 bits */ if (pci_set_dma_mask(pci, DMA_31BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_31BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support " "31bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (!codec) { pci_disable_device(pci); return -ENOMEM; } spin_lock_init(&codec->reg_lock); spin_lock_init(&codec->voice_alloc); codec->card = card; codec->pci = pci; codec->irq = -1; codec->revision = pci->revision; codec->spdif_support = spdif_support; 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)) { snd_ali_free(codec); return -EBUSY; } synchronize_irq(pci->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; /* M1533: southbridge */ codec->pci_m1533 = pci_get_device(0x10b9, 0x1533, NULL); if (!codec->pci_m1533) { snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n"); snd_ali_free(codec); return -ENODEV; } /* M7101: power management */ codec->pci_m7101 = pci_get_device(0x10b9, 0x7101, NULL); if (!codec->pci_m7101 && codec->revision == ALI_5451_V02) { snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n"); snd_ali_free(codec); return -ENODEV; } snd_ali_printk("snd_device_new is called.\n"); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops); if (err < 0) { snd_ali_free(codec); return err; } snd_card_set_dev(card, &pci->dev); /* initialise synth voices*/ for (i = 0; i < ALI_CHANNELS; i++) codec->synth.voices[i].number = i; err = snd_ali_chip_init(codec); if (err < 0) { snd_printk(KERN_ERR "ali create: chip init error.\n"); return err; }#ifdef CONFIG_PM codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL); if (!codec->image) snd_printk(KERN_WARNING "can't allocate apm buffer\n");#endif snd_ali_enable_address_interrupt(codec); codec->hw_initialized = 1; *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 *pci_id){ struct snd_card *card; struct snd_ali *codec; int err; snd_ali_printk("probe ...\n"); card = snd_card_new(index, id, THIS_MODULE, 0); if (!card) return -ENOMEM; err = snd_ali_create(card, pci, pcm_channels, spdif, &codec); if (err < 0) goto error; card->private_data = codec; snd_ali_printk("mixer building ...\n"); err = snd_ali_mixer(codec); if (err < 0) goto error; snd_ali_printk("pcm building ...\n"); err = snd_ali_build_pcms(codec); if (err < 0) goto error; snd_ali_proc_init(codec); strcpy(card->driver, "ALI5451"); strcpy(card->shortname, "ALI 5451"); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, codec->port, codec->irq); snd_ali_printk("register card.\n"); err = snd_card_register(card); if (err < 0) goto error; pci_set_drvdata(pci, card); return 0; error: snd_card_free(card); return err;}static void __devexit snd_ali_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); 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 = ali_suspend, .resume = ali_resume,#endif}; static int __init alsa_card_ali_init(void){ return pci_register_driver(&driver);}static void __exit alsa_card_ali_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_ali_init)module_exit(alsa_card_ali_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -