📄 atiixp.c
字号:
int err; down(&chip->open_mutex); if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */ err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2); else err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1); up(&chip->open_mutex); return err;}static int snd_atiixp_spdif_close(snd_pcm_substream_t *substream){ atiixp_t *chip = snd_pcm_substream_chip(substream); int err; down(&chip->open_mutex); if (chip->spdif_over_aclink) err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); else err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); up(&chip->open_mutex); return err;}/* AC97 playback */static snd_pcm_ops_t snd_atiixp_playback_ops = { .open = snd_atiixp_playback_open, .close = snd_atiixp_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_atiixp_pcm_hw_params, .hw_free = snd_atiixp_pcm_hw_free, .prepare = snd_atiixp_playback_prepare, .trigger = snd_atiixp_pcm_trigger, .pointer = snd_atiixp_pcm_pointer,};/* AC97 capture */static snd_pcm_ops_t snd_atiixp_capture_ops = { .open = snd_atiixp_capture_open, .close = snd_atiixp_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_atiixp_pcm_hw_params, .hw_free = snd_atiixp_pcm_hw_free, .prepare = snd_atiixp_capture_prepare, .trigger = snd_atiixp_pcm_trigger, .pointer = snd_atiixp_pcm_pointer,};/* SPDIF playback */static snd_pcm_ops_t snd_atiixp_spdif_ops = { .open = snd_atiixp_spdif_open, .close = snd_atiixp_spdif_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_atiixp_pcm_hw_params, .hw_free = snd_atiixp_pcm_hw_free, .prepare = snd_atiixp_spdif_prepare, .trigger = snd_atiixp_pcm_trigger, .pointer = snd_atiixp_pcm_pointer,};static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = { /* front PCM */ { .exclusive = 1, .r = { { .slots = (1 << AC97_SLOT_PCM_LEFT) | (1 << AC97_SLOT_PCM_RIGHT) | (1 << AC97_SLOT_PCM_CENTER) | (1 << AC97_SLOT_PCM_SLEFT) | (1 << AC97_SLOT_PCM_SRIGHT) | (1 << AC97_SLOT_LFE) } } }, /* PCM IN #1 */ { .stream = 1, .exclusive = 1, .r = { { .slots = (1 << AC97_SLOT_PCM_LEFT) | (1 << AC97_SLOT_PCM_RIGHT) } } }, /* S/PDIF OUT (optional) */ { .exclusive = 1, .spdif = 1, .r = { { .slots = (1 << AC97_SLOT_SPDIF_LEFT2) | (1 << AC97_SLOT_SPDIF_RIGHT2) } } },};static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_OUT_DMA_LINKPTR, .dt_cur = ATI_REG_OUT_DMA_DT_CUR, .enable_dma = atiixp_out_enable_dma, .enable_transfer = atiixp_out_enable_transfer, .flush_dma = atiixp_out_flush_dma,}; static atiixp_dma_ops_t snd_atiixp_capture_dma_ops = { .type = ATI_DMA_CAPTURE, .llp_offset = ATI_REG_IN_DMA_LINKPTR, .dt_cur = ATI_REG_IN_DMA_DT_CUR, .enable_dma = atiixp_in_enable_dma, .enable_transfer = atiixp_in_enable_transfer, .flush_dma = atiixp_in_flush_dma,}; static atiixp_dma_ops_t snd_atiixp_spdif_dma_ops = { .type = ATI_DMA_SPDIF, .llp_offset = ATI_REG_SPDF_DMA_LINKPTR, .dt_cur = ATI_REG_SPDF_DMA_DT_CUR, .enable_dma = atiixp_spdif_enable_dma, .enable_transfer = atiixp_spdif_enable_transfer, .flush_dma = atiixp_spdif_flush_dma,}; static int __devinit snd_atiixp_pcm_new(atiixp_t *chip){ snd_pcm_t *pcm; ac97_bus_t *pbus = chip->ac97_bus; int err, i, num_pcms; /* initialize constants */ chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops; chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops; if (! chip->spdif_over_aclink) chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops; /* assign AC97 pcm */ if (chip->spdif_over_aclink) num_pcms = 3; else num_pcms = 2; err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs); if (err < 0) return err; for (i = 0; i < num_pcms; i++) chip->pcms[i] = &pbus->pcms[i]; chip->max_channels = 2; if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { if (pbus->pcms[ATI_PCM_OUT].r[0].slots & (1 << AC97_SLOT_LFE)) chip->max_channels = 6; else chip->max_channels = 4; } /* PCM #0: analog I/O */ err = snd_pcm_new(chip->card, "ATI IXP AC97", ATI_PCMDEV_ANALOG, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops); pcm->private_data = chip; strcpy(pcm->name, "ATI IXP AC97"); chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 128*1024); /* no SPDIF support on codec? */ if (chip->pcms[ATI_PCM_SPDIF] && ! chip->pcms[ATI_PCM_SPDIF]->rates) return 0; /* FIXME: non-48k sample rate doesn't work on my test machine with AD1888 */ if (chip->pcms[ATI_PCM_SPDIF]) chip->pcms[ATI_PCM_SPDIF]->rates = SNDRV_PCM_RATE_48000; /* PCM #1: spdif playback */ err = snd_pcm_new(chip->card, "ATI IXP IEC958", ATI_PCMDEV_DIGITAL, 1, 0, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops); pcm->private_data = chip; if (chip->spdif_over_aclink) strcpy(pcm->name, "ATI IXP IEC958 (AC97)"); else strcpy(pcm->name, "ATI IXP IEC958 (Direct)"); chip->pcmdevs[ATI_PCMDEV_DIGITAL] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 128*1024); /* pre-select AC97 SPDIF slots 10/11 */ for (i = 0; i < NUM_ATI_CODECS; i++) { if (chip->ac97[i]) snd_ac97_update_bits(chip->ac97[i], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4); } return 0;}/* * interrupt handler */static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs){ atiixp_t *chip = dev_id; unsigned int status; status = atiixp_read(chip, ISR); if (! status) return IRQ_NONE; /* process audio DMA */ if (status & ATI_REG_ISR_OUT_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); else if (status & ATI_REG_ISR_OUT_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); if (status & ATI_REG_ISR_IN_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); else if (status & ATI_REG_ISR_IN_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); if (! chip->spdif_over_aclink) { if (status & ATI_REG_ISR_SPDF_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); else if (status & ATI_REG_ISR_SPDF_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); } /* for codec detection */ if (status & CODEC_CHECK_BITS) { unsigned int detected; detected = status & CODEC_CHECK_BITS; spin_lock(&chip->reg_lock); chip->codec_not_ready_bits |= detected; atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */ spin_unlock(&chip->reg_lock); } /* ack */ atiixp_write(chip, ISR, status); return IRQ_HANDLED;}/* * ac97 mixer section */static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock){ ac97_bus_t *pbus; ac97_template_t ac97; int i, err; int codec_count; static ac97_bus_ops_t ops = { .write = snd_atiixp_ac97_write, .read = snd_atiixp_ac97_read, }; static unsigned int codec_skip[NUM_ATI_CODECS] = { ATI_REG_ISR_CODEC0_NOT_READY, ATI_REG_ISR_CODEC1_NOT_READY, ATI_REG_ISR_CODEC2_NOT_READY, }; if (snd_atiixp_codec_detect(chip) < 0) return -ENXIO; if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) return err; pbus->clock = clock; pbus->shared_type = AC97_SHARED_TYPE_ATIIXP; /* shared with modem driver */ chip->ac97_bus = pbus; codec_count = 0; for (i = 0; i < NUM_ATI_CODECS; i++) { if (chip->codec_not_ready_bits & codec_skip[i]) continue; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.pci = chip->pci; ac97.num = i; ac97.scaps = AC97_SCAP_SKIP_MODEM; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* to be sure */ snd_printdd("atiixp: codec %d not available for audio\n", i); continue; } codec_count++; } if (! codec_count) { snd_printk(KERN_ERR "atiixp: no codec available\n"); return -ENODEV; } /* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */ return 0;}#ifdef CONFIG_PM/* * power management */static int snd_atiixp_suspend(snd_card_t *card, unsigned int state){ atiixp_t *chip = card->pm_private_data; int i; for (i = 0; i < NUM_ATI_PCMDEVS; i++) if (chip->pcmdevs[i]) snd_pcm_suspend_all(chip->pcmdevs[i]); for (i = 0; i < NUM_ATI_CODECS; i++) if (chip->ac97[i]) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); snd_atiixp_chip_stop(chip); pci_set_power_state(chip->pci, 3); pci_disable_device(chip->pci); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); return 0;}static int snd_atiixp_resume(snd_card_t *card, unsigned int state){ atiixp_t *chip = card->pm_private_data; int i; pci_enable_device(chip->pci); pci_set_power_state(chip->pci, 0); snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); for (i = 0; i < NUM_ATI_CODECS; i++) if (chip->ac97[i]) snd_ac97_resume(chip->ac97[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0;}#endif /* CONFIG_PM *//* * proc interface for register dump */static void snd_atiixp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer){ atiixp_t *chip = entry->private_data; int i; for (i = 0; i < 256; i += 4) snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i));}static void __devinit snd_atiixp_proc_init(atiixp_t *chip){ snd_info_entry_t *entry; if (! snd_card_proc_new(chip->card, "atiixp", &entry)) snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read);}/* * destructor */static int snd_atiixp_free(atiixp_t *chip){ if (chip->irq < 0) goto __hw_end; snd_atiixp_chip_stop(chip); synchronize_irq(chip->irq); __hw_end: if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); if (chip->remap_addr) iounmap(chip->remap_addr); pci_release_regions(chip->pci); kfree(chip); return 0;}static int snd_atiixp_dev_free(snd_device_t *device){ atiixp_t *chip = device->device_data; return snd_atiixp_free(chip);}/* * constructor for chip instance */static int __devinit snd_atiixp_create(snd_card_t *card, struct pci_dev *pci, atiixp_t **r_chip){ static snd_device_ops_t ops = { .dev_free = snd_atiixp_dev_free, }; atiixp_t *chip; int err; if ((err = pci_enable_device(pci)) < 0) return err; chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->ac97_lock); init_MUTEX(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; if ((err = pci_request_regions(pci, "ATI IXP AC97")) < 0) { kfree(chip); return err; } chip->addr = pci_resource_start(pci, 0); chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci, 0)); if (chip->remap_addr == 0) { snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); snd_atiixp_free(chip); return -EIO; } if (request_irq(pci->irq, snd_atiixp_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_atiixp_free(chip); return err; } snd_card_set_dev(card, &pci->dev); *r_chip = chip; return 0;}static int __devinit snd_atiixp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; snd_card_t *card; atiixp_t *chip; unsigned char revision; int err; if (dev >= SNDRV_CARDS) return -ENODEV; if (!enable[dev]) { dev++; return -ENOENT; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; pci_read_config_byte(pci, PCI_REVISION_ID, &revision); strcpy(card->driver, spdif_aclink[dev] ? "ATIIXP" : "ATIIXP-SPDMA"); strcpy(card->shortname, "ATI IXP"); if ((err = snd_atiixp_create(card, pci, &chip)) < 0) goto __error; if ((err = snd_atiixp_aclink_reset(chip)) < 0) goto __error; chip->spdif_over_aclink = spdif_aclink[dev]; if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev])) < 0) goto __error; if ((err = snd_atiixp_pcm_new(chip)) < 0) goto __error; snd_atiixp_proc_init(chip); snd_atiixp_chip_start(chip); sprintf(card->longname, "%s rev %x at 0x%lx, irq %i", card->shortname, revision, chip->addr, chip->irq); snd_card_set_pm_callback(card, snd_atiixp_suspend, snd_atiixp_resume, chip); if ((err = snd_card_register(card)) < 0) goto __error; pci_set_drvdata(pci, card); dev++; return 0; __error: snd_card_free(card); return err;}static void __devexit snd_atiixp_remove(struct pci_dev *pci){ snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL);}static struct pci_driver driver = { .name = "ATI IXP AC97 controller", .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), SND_PCI_PM_CALLBACKS};static int __init alsa_card_atiixp_init(void){ return pci_module_init(&driver);}static void __exit alsa_card_atiixp_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_atiixp_init)module_exit(alsa_card_atiixp_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -