atiixp_modem.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,352 行 · 第 1/3 页
C
1,352 行
spin_lock_irq(&chip->reg_lock); dma->ops->enable_dma(chip, 0); spin_unlock_irq(&chip->reg_lock); dma->substream = NULL; dma->opened = 0; return 0;}/* */static int snd_atiixp_playback_open(snd_pcm_substream_t *substream){ atiixp_t *chip = snd_pcm_substream_chip(substream); int err; down(&chip->open_mutex); err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); up(&chip->open_mutex); if (err < 0) return err; return 0;}static int snd_atiixp_playback_close(snd_pcm_substream_t *substream){ atiixp_t *chip = snd_pcm_substream_chip(substream); int err; down(&chip->open_mutex); err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); up(&chip->open_mutex); return err;}static int snd_atiixp_capture_open(snd_pcm_substream_t *substream){ atiixp_t *chip = snd_pcm_substream_chip(substream); return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1);}static int snd_atiixp_capture_close(snd_pcm_substream_t *substream){ atiixp_t *chip = snd_pcm_substream_chip(substream); return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]);}/* 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,};static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR, .dt_cur = ATI_REG_MODEM_OUT_DMA1_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_MODEM_IN_DMA_LINKPTR, .dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR, .enable_dma = atiixp_in_enable_dma, .enable_transfer = atiixp_in_enable_transfer, .flush_dma = atiixp_in_flush_dma,};static int __devinit snd_atiixp_pcm_new(atiixp_t *chip){ snd_pcm_t *pcm; int err; /* initialize constants */ chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops; chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops; /* PCM #0: analog I/O */ err = snd_pcm_new(chip->card, "ATI IXP MC97", 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 MC97"); 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); 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_MODEM_OUT1_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); else if (status & ATI_REG_ISR_MODEM_OUT1_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); if (status & ATI_REG_ISR_MODEM_IN_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); else if (status & ATI_REG_ISR_MODEM_IN_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); /* 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 audio 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_AUDIO; 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 modem\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 MC97")) < 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, "ATIIXP-MODEM"); strcpy(card->shortname, "ATI IXP Modem"); if ((err = snd_atiixp_create(card, pci, &chip)) < 0) goto __error; if ((err = snd_atiixp_aclink_reset(chip)) < 0) goto __error; 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 MC97 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 + =
减小字号Ctrl + -
显示快捷键?