📄 nm256.c
字号:
snd_nm256_ac97_read(ac97_t *ac97, unsigned short reg){ nm256_t *chip = snd_magic_cast(nm256_t, ac97->private_data, return -ENXIO); int res; if (reg >= 128) return 0; if (! snd_nm256_ac97_ready(chip)) return 0; res = snd_nm256_readw(chip, chip->mixer_base + reg); /* Magic delay. Bleah yucky. */ udelay(1000); return res;}/* */static voidsnd_nm256_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val){ nm256_t *chip = snd_magic_cast(nm256_t, ac97->private_data, return); int tries = 2; u32 base; base = chip->mixer_base; snd_nm256_ac97_ready(chip); /* Wait for the write to take, too. */ while (tries-- > 0) { snd_nm256_writew(chip, base + reg, val); udelay(1000); /* a little delay here seems better.. */ if (snd_nm256_ac97_ready(chip)) return; } snd_printd("nm256: ac97 codec not ready..\n");}/* initialize the ac97 into a known state */static voidsnd_nm256_ac97_reset(ac97_t *ac97){ nm256_t *chip = snd_magic_cast(nm256_t, ac97->private_data, return); unsigned long flags; spin_lock_irqsave(&chip->reg_lock, flags); /* Reset the mixer. 'Tis magic! */ snd_nm256_writeb(chip, 0x6c0, 1);#if 0 /* Dell latitude LS will lock up by this */ snd_nm256_writeb(chip, 0x6cc, 0x87);#endif snd_nm256_writeb(chip, 0x6cc, 0x80); snd_nm256_writeb(chip, 0x6cc, 0x0); spin_unlock_irqrestore(&chip->reg_lock, flags);}/* create an ac97 mixer interface */static int __initsnd_nm256_mixer(nm256_t *chip){ ac97_t ac97; int err; memset(&ac97, 0, sizeof(ac97)); ac97.init = snd_nm256_ac97_reset; ac97.write = snd_nm256_ac97_write; ac97.read = snd_nm256_ac97_read; ac97.private_data = chip; if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0) return err; return 0;}/* * See if the signature left by the NM256 BIOS is intact; if so, we use * the associated address as the end of our audio buffer in the video * RAM. */static int __initsnd_nm256_peek_for_sig(nm256_t *chip){ /* The signature is located 1K below the end of video RAM. */ unsigned long temp; /* Default buffer end is 5120 bytes below the top of RAM. */ unsigned long pointer_found = chip->buffer_end - 0x1400; u32 sig; temp = (unsigned long) ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16); if (temp == 0) { snd_printk("Unable to scan for card signature in video RAM\n"); return -EBUSY; } sig = readl(temp); if ((sig & NM_SIG_MASK) == NM_SIGNATURE) { u32 pointer = readl(temp + 4); /* * If it's obviously invalid, don't use it */ if (pointer == 0xffffffff || pointer < chip->buffer_size || pointer > chip->buffer_end) { snd_printk("invalid signature found: 0x%x\n", pointer); iounmap((void *)temp); return -ENODEV; } else { pointer_found = pointer; printk(KERN_INFO "nm256: found card signature in video RAM: 0x%x\n", pointer); } } iounmap((void *)temp); chip->buffer_end = pointer_found; return 0;}#ifdef CONFIG_PM/* * APM event handler, so the card is properly reinitialized after a power * event. */static void nm256_suspend(nm256_t *chip){ snd_card_t *card = chip->card; snd_power_lock(card); if (card->power_state == SNDRV_CTL_POWER_D3hot) goto __skip; snd_pcm_suspend_all(chip->pcm); chip->coeffs_current = 0; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); __skip: snd_power_unlock(card);}static void nm256_resume(nm256_t *chip){ snd_card_t *card = chip->card; snd_power_lock(card); if (card->power_state == SNDRV_CTL_POWER_D0) goto __skip; /* Perform a full reset on the hardware */ pci_enable_device(chip->pci); snd_nm256_init_chip(chip); /* restore ac97 */ snd_ac97_resume(chip->ac97); snd_power_change_state(card, SNDRV_CTL_POWER_D0); __skip: snd_power_unlock(card);}#ifndef PCI_OLD_SUSPENDstatic int snd_nm256_suspend(struct pci_dev *dev, u32 state){ nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return -ENXIO); nm256_suspend(chip); return 0;}static int snd_nm256_resume(struct pci_dev *dev){ nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return -ENXIO); nm256_resume(chip); return 0;}#elsestatic void snd_nm256_suspend(struct pci_dev *dev){ nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return); nm256_suspend(chip);}static void snd_nm256_resume(struct pci_dev *dev){ nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(dev), return); nm256_resume(chip);}#endif/* callback */static int snd_nm256_set_power_state(snd_card_t *card, unsigned int power_state){ nm256_t *chip = snd_magic_cast(nm256_t, card->power_state_private_data, return -ENXIO); switch (power_state) { case SNDRV_CTL_POWER_D0: case SNDRV_CTL_POWER_D1: case SNDRV_CTL_POWER_D2: nm256_resume(chip); break; case SNDRV_CTL_POWER_D3hot: case SNDRV_CTL_POWER_D3cold: nm256_suspend(chip); break; default: return -EINVAL; } return 0;}#endif /* CONFIG_PM */static int snd_nm256_free(nm256_t *chip){ if (chip->streams[SNDRV_PCM_STREAM_PLAYBACK].running) snd_nm256_playback_stop(chip); if (chip->streams[SNDRV_PCM_STREAM_CAPTURE].running) snd_nm256_capture_stop(chip); synchronize_irq(); if (chip->cport) iounmap((void *) chip->cport); if (chip->buffer) iounmap((void *) chip->buffer); if (chip->res_cport) { release_resource(chip->res_cport); kfree_nocheck(chip->res_cport); } if (chip->res_buffer) { release_resource(chip->res_buffer); kfree_nocheck(chip->res_buffer); } if (chip->irq >= 0) free_irq(chip->irq, (void*)chip); snd_magic_kfree(chip); return 0;}static int snd_nm256_dev_free(snd_device_t *device){ nm256_t *chip = snd_magic_cast(nm256_t, device->device_data, return -ENXIO); return snd_nm256_free(chip);}static int __initsnd_nm256_create(snd_card_t *card, struct pci_dev *pci, int play_bufsize, int capt_bufsize, int force_load, u32 buffertop, int usecache, nm256_t **chip_ret){ nm256_t *chip; int err, pval; static snd_device_ops_t ops = { dev_free: snd_nm256_dev_free, }; u32 addr; *chip_ret = NULL; chip = snd_magic_kcalloc(nm256_t, 0, GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->card = card; chip->pci = pci; chip->use_cache = usecache; spin_lock_init(&chip->reg_lock); chip->irq = -1; chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize = play_bufsize; chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize = capt_bufsize; /* * The NM256 has two memory ports. The first port is nothing * more than a chunk of video RAM, which is used as the I/O ring * buffer. The second port has the actual juicy stuff (like the * mixer and the playback engine control registers). */ chip->buffer_addr = pci_resource_start(pci, 0); chip->cport_addr = pci_resource_start(pci, 1); /* Init the memory port info. */ /* remap control port (#2) */ chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE, card->driver); if (chip->res_cport == NULL) { snd_printk("memory region 0x%lx (size 0x%x) busy\n", chip->cport_addr, NM_PORT2_SIZE); err = -EBUSY; goto __error; } chip->cport = (unsigned long) ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE); if (chip->cport == 0) { snd_printk("unable to map control port %lx\n", chip->cport_addr); err = -ENOMEM; goto __error; } if (!strcmp(card->driver, "NM256AV")) { /* Ok, try to see if this is a non-AC97 version of the hardware. */ pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE); if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) { if (! force_load) { printk(KERN_ERR "nm256: no ac97 is found!\n"); printk(KERN_ERR " force the driver to load by passing in the module parameter\n"); printk(KERN_ERR " snd_force_ac97=1\n"); printk(KERN_ERR " or try sb16 or cs423x drivers instead.\n"); err = -ENXIO; goto __error; } } chip->buffer_end = 2560 * 1024; chip->interrupt = snd_nm256_interrupt; chip->mixer_status_offset = NM_MIXER_STATUS_OFFSET; chip->mixer_status_mask = NM_MIXER_READY_MASK; } else { /* Not sure if there is any relevant detect for the ZX or not. */ if (snd_nm256_readb(chip, 0xa0b) != 0) chip->buffer_end = 6144 * 1024; else chip->buffer_end = 4096 * 1024; chip->interrupt = snd_nm256_interrupt_zx; chip->mixer_status_offset = NM2_MIXER_STATUS_OFFSET; chip->mixer_status_mask = NM2_MIXER_READY_MASK; } chip->buffer_size = chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize + chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize; if (chip->use_cache) chip->buffer_size += NM_TOTAL_COEFF_COUNT * 4; else chip->buffer_size += NM_MAX_PLAYBACK_COEF_SIZE + NM_MAX_RECORD_COEF_SIZE; if (buffertop >= chip->buffer_size && buffertop < chip->buffer_end) chip->buffer_end = buffertop; else { /* get buffer end pointer from signature */ if ((err = snd_nm256_peek_for_sig(chip)) < 0) goto __error; } chip->buffer_start = chip->buffer_end - chip->buffer_size; chip->buffer_addr += chip->buffer_start; printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n", chip->buffer_start, chip->buffer_end); chip->res_buffer = request_mem_region(chip->buffer_addr, chip->buffer_size, card->driver); if (chip->res_buffer == NULL) { snd_printk("nm256: buffer 0x%lx (size 0x%x) busy\n", chip->buffer_addr, chip->buffer_size); err = -EBUSY; goto __error; } chip->buffer = (unsigned long) ioremap_nocache(chip->buffer_addr, chip->buffer_size); if (chip->buffer == 0) { err = -ENOMEM; snd_printk("unable to map ring buffer at %lx\n", chip->buffer_addr); goto __error; } /* set offsets */ addr = chip->buffer_start; chip->streams[SNDRV_PCM_STREAM_PLAYBACK].buf = addr; addr += chip->streams[SNDRV_PCM_STREAM_PLAYBACK].bufsize; chip->streams[SNDRV_PCM_STREAM_CAPTURE].buf = addr; addr += chip->streams[SNDRV_PCM_STREAM_CAPTURE].bufsize; if (chip->use_cache) { chip->all_coeff_buf = addr; } else { chip->coeff_buf[SNDRV_PCM_STREAM_PLAYBACK] = addr; addr += NM_MAX_PLAYBACK_COEF_SIZE; chip->coeff_buf[SNDRV_PCM_STREAM_CAPTURE] = addr; } /* acquire interrupt */ if (request_irq(pci->irq, chip->interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void*)chip)) { err = -EBUSY; snd_printk("unable to grab IRQ %d\n", pci->irq); goto __error; } chip->irq = pci->irq; /* Fixed setting. */ chip->mixer_base = NM_MIXER_OFFSET; chip->coeffs_current = 0; snd_nm256_init_chip(chip); if ((err = snd_nm256_pcm(chip, 0)) < 0) goto __error; if ((err = snd_nm256_mixer(chip) < 0)) goto __error; // pci_set_master(pci); /* needed? */ #ifdef CONFIG_PM card->set_power_state = snd_nm256_set_power_state; card->power_state_private_data = chip;#endif if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; *chip_ret = chip; return 0;__error: snd_nm256_free(chip); return err;}static int __devinit snd_nm256_probe(struct pci_dev *pci, const struct pci_device_id *id){ static int dev; snd_card_t *card; nm256_t *chip; int err; unsigned int buffer_top; if ((err = pci_enable_device(pci)) < 0) return err; 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; switch (pci->device) { case PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO: strcpy(card->driver, "NM256AV"); break; case PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO: strcpy(card->driver, "NM256ZX"); break; default: snd_printk("invalid device id 0x%x\n", pci->device); snd_card_free(card); return -EINVAL; } if (snd_vaio_hack[dev]) buffer_top = 0x25a800; /* this avoids conflicts with XFree86 server */ else buffer_top = snd_buffer_top[dev]; if (snd_playback_bufsize[dev] < 4) snd_playback_bufsize[dev] = 4; if (snd_playback_bufsize[dev] > 128) snd_playback_bufsize[dev] = 128; if (snd_capture_bufsize[dev] < 4) snd_capture_bufsize[dev] = 4; if (snd_capture_bufsize[dev] > 128) snd_capture_bufsize[dev] = 128; if ((err = snd_nm256_create(card, pci, snd_playback_bufsize[dev] * 1024, /* in bytes */ snd_capture_bufsize[dev] * 1024, /* in bytes */ snd_force_ac97[dev], buffer_top, snd_use_cache[dev], &chip)) < 0) { snd_card_free(card); return err; } sprintf(card->shortname, "NeoMagic %s", card->driver); sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %d", card->shortname, chip->buffer_addr, chip->cport_addr, chip->irq); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; } pci_set_drvdata(pci, chip); dev++; return 0;}static void __devexit snd_nm256_remove(struct pci_dev *pci){ nm256_t *chip = snd_magic_cast(nm256_t, pci_get_drvdata(pci), return); if (chip) snd_card_free(chip->card); pci_set_drvdata(pci, NULL);}static struct pci_driver driver = { name: "NeoMagic 256", id_table: snd_nm256_ids, probe: snd_nm256_probe, remove: __devexit_p(snd_nm256_remove),#ifdef CONFIG_PM suspend: snd_nm256_suspend, resume: snd_nm256_resume,#endif};static int __init alsa_card_nm256_init(void){ int err; if ((err = pci_module_init(&driver)) < 0) {#ifdef MODULE printk(KERN_ERR "NeoMagic 256 audio soundchip not found or device busy\n");#endif return err; } return 0;}static void __exit alsa_card_nm256_exit(void){ pci_unregister_driver(&driver);}module_init(alsa_card_nm256_init)module_exit(alsa_card_nm256_exit)#ifndef MODULE/* format is: snd-nm256=snd_enable,snd_index,snd_id, snd_playback_bufsize,snd_capture_bufsize, snd_force_ac97,snd_buffer_top,snd_use_cache */static int __init alsa_card_nm256_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_playback_bufsize[nr_dev]) == 2 && get_option(&str,&snd_capture_bufsize[nr_dev]) == 2 && get_option(&str,&snd_force_ac97[nr_dev]) == 2 && get_option(&str,&snd_buffer_top[nr_dev]) == 2 && get_option(&str,&snd_use_cache[nr_dev]) == 2); nr_dev++; return 1;}__setup("snd-nm256=", alsa_card_nm256_setup);#endif /* ifndef MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -