📄 azt3328.c
字号:
snd_azf3328_dbgcallenter(); *num = 1; *den = 1024000 / seqtimer_scaling; snd_azf3328_dbgcallleave(); return 0;}static struct snd_timer_hardware snd_azf3328_timer_hw = { .flags = SNDRV_TIMER_HW_AUTO, .resolution = 977, /* 1000000/1024000 = 0.9765625us */ .ticks = 1024000, /* max tick count, defined by the value register; actually it's not 1024000, but 1048576, but we don't care */ .start = snd_azf3328_timer_start, .stop = snd_azf3328_timer_stop, .precise_resolution = snd_azf3328_timer_precise_resolution,};static int __devinitsnd_azf3328_timer(struct snd_azf3328 *chip, int device){ struct snd_timer *timer = NULL; struct snd_timer_id tid; int err; snd_azf3328_dbgcallenter(); tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = chip->card->number; tid.device = device; tid.subdevice = 0; snd_azf3328_timer_hw.resolution *= seqtimer_scaling; snd_azf3328_timer_hw.ticks /= seqtimer_scaling; if ((err = snd_timer_new(chip->card, "AZF3328", &tid, &timer)) < 0) { goto out; } strcpy(timer->name, "AZF3328 timer"); timer->private_data = chip; timer->hw = snd_azf3328_timer_hw; chip->timer = timer; err = 0;out: snd_azf3328_dbgcallleave(); return err;}/******************************************************************/#if 0/* check whether a bit can be modified */static voidsnd_azf3328_test_bit(unsigned int reg, int bit){ unsigned char val, valoff, valon; val = inb(reg); outb(val & ~(1 << bit), reg); valoff = inb(reg); outb(val|(1 << bit), reg); valon = inb(reg); outb(val, reg); printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon);}#endif#if DEBUG_MISCstatic voidsnd_azf3328_debug_show_ports(const struct snd_azf3328 *chip){ u16 tmp; snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_inb(chip, 0), snd_azf3328_io2_inb(chip, 1), snd_azf3328_io2_inb(chip, 2), snd_azf3328_io2_inb(chip, 3), snd_azf3328_io2_inb(chip, 4), snd_azf3328_io2_inb(chip, 5)); for (tmp=0; tmp <= 0x01; tmp += 1) snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", tmp, snd_azf3328_codec_inw(chip, tmp)); for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", tmp, snd_azf3328_mixer_inw(chip, tmp));}#elsestatic inline voidsnd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) {}#endifstatic int __devinitsnd_azf3328_create(struct snd_card *card, struct pci_dev *pci, unsigned long device_type, struct snd_azf3328 ** rchip){ struct snd_azf3328 *chip; int err; static struct snd_device_ops ops = { .dev_free = snd_azf3328_dev_free, }; u16 tmp; *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { err = -ENOMEM; goto out_err; } spin_lock_init(&chip->reg_lock); chip->card = card; chip->pci = pci; chip->irq = -1; /* check if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_24BIT_MASK) < 0 || pci_set_consistent_dma_mask(pci, DMA_24BIT_MASK) < 0) { snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); err = -ENXIO; goto out_err; } if ((err = pci_request_regions(pci, "Aztech AZF3328")) < 0) { goto out_err; } chip->codec_port = pci_resource_start(pci, 0); chip->io2_port = pci_resource_start(pci, 1); chip->mpu_port = pci_resource_start(pci, 2); chip->synth_port = pci_resource_start(pci, 3); chip->mixer_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_azf3328_interrupt, IRQF_SHARED, card->shortname, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto out_err; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); snd_azf3328_debug_show_ports(chip); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { goto out_err; } /* create mixer interface & switches */ if ((err = snd_azf3328_mixer_new(chip)) < 0) goto out_err;#if 0 /* set very low bitrate to reduce noise and power consumption? */ snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1);#endif /* standard chip init stuff */ /* default IRQ init value */ tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; spin_lock_irq(&chip->reg_lock); snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x00); /* disable timer */ spin_unlock_irq(&chip->reg_lock); snd_card_set_dev(card, &pci->dev); *rchip = chip; err = 0; goto out;out_err: if (chip) snd_azf3328_free(chip); pci_disable_device(pci);out: return err;}static int __devinitsnd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id){ static int dev; struct snd_card *card; struct snd_azf3328 *chip; struct snd_opl3 *opl3; int err; snd_azf3328_dbgcallenter(); 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; strcpy(card->driver, "AZF3328"); strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) { goto out_err; } card->private_data = chip; if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, chip->mpu_port, MPU401_INFO_INTEGRATED, pci->irq, 0, &chip->rmidi)) < 0) { snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); goto out_err; } if ((err = snd_azf3328_timer(chip, 0)) < 0) { goto out_err; } if ((err = snd_azf3328_pcm(chip, 0)) < 0) { goto out_err; } if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2, OPL3_HW_AUTO, 1, &opl3) < 0) { snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", chip->synth_port, chip->synth_port+2 ); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { goto out_err; } } opl3->private_data = chip; sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->codec_port, chip->irq); if ((err = snd_card_register(card)) < 0) { goto out_err; }#ifdef MODULE printk("azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n""azt3328: Hardware was completely undocumented, unfortunately.\n""azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n""azt3328: User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n", 1024000 / seqtimer_scaling, seqtimer_scaling);#endif if (snd_azf3328_config_joystick(chip, dev) < 0) snd_azf3328_io2_outb(chip, IDX_IO2_LEGACY_ADDR, snd_azf3328_io2_inb(chip, IDX_IO2_LEGACY_ADDR) & ~LEGACY_JOY); pci_set_drvdata(pci, card); dev++; err = 0; goto out; out_err: snd_card_free(card); out: snd_azf3328_dbgcallleave(); return err;}static void __devexitsnd_azf3328_remove(struct pci_dev *pci){ snd_azf3328_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); snd_azf3328_dbgcallleave();}#ifdef CONFIG_PMstatic intsnd_azf3328_suspend(struct pci_dev *pci, pm_message_t state){ struct snd_card *card = pci_get_drvdata(pci); struct snd_azf3328 *chip = card->private_data; int reg; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) chip->saved_regs_mixer[reg] = inw(chip->mixer_port + reg * 2); /* make sure to disable master volume etc. to prevent looping sound */ snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) chip->saved_regs_codec[reg] = inw(chip->codec_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) chip->saved_regs_io2[reg] = inw(chip->io2_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) chip->saved_regs_mpu[reg] = inw(chip->mpu_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) chip->saved_regs_synth[reg] = inw(chip->synth_port + reg * 2); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0;}static intsnd_azf3328_resume(struct pci_dev *pci){ struct snd_card *card = pci_get_drvdata(pci); struct snd_azf3328 *chip = card->private_data; int reg; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "azt3328: pci_enable_device failed, " "disabling device\n"); snd_card_disconnect(card); return -EIO; } pci_set_master(pci); for (reg = 0; reg < AZF_IO_SIZE_IO2_PM / 2; reg++) outw(chip->saved_regs_io2[reg], chip->io2_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; reg++) outw(chip->saved_regs_mpu[reg], chip->mpu_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_SYNTH_PM / 2; reg++) outw(chip->saved_regs_synth[reg], chip->synth_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; reg++) outw(chip->saved_regs_mixer[reg], chip->mixer_port + reg * 2); for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; reg++) outw(chip->saved_regs_codec[reg], chip->codec_port + reg * 2); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0;}#endifstatic struct pci_driver driver = { .name = "AZF3328", .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, .remove = __devexit_p(snd_azf3328_remove),#ifdef CONFIG_PM .suspend = snd_azf3328_suspend, .resume = snd_azf3328_resume,#endif};static int __initalsa_card_azf3328_init(void){ int err; snd_azf3328_dbgcallenter(); err = pci_register_driver(&driver); snd_azf3328_dbgcallleave(); return err;}static void __exitalsa_card_azf3328_exit(void){ snd_azf3328_dbgcallenter(); pci_unregister_driver(&driver); snd_azf3328_dbgcallleave();}module_init(alsa_card_azf3328_init)module_exit(alsa_card_azf3328_exit)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -