📄 opl3sa2.c
字号:
unsigned char sys_ctrl; opl3sa2_read(hw_config->io_base, OPL3SA2_SYS_CTRL, &sys_ctrl); sys_ctrl = (sys_ctrl & 0xcf) | ((ymode & 3) << 4); opl3sa2_write(hw_config->io_base, OPL3SA2_SYS_CTRL, sys_ctrl); } else { printk(KERN_ERR "opl3sa2: not setting ymode, it must be one of 0,1,2,3\n"); }}static void __init opl3sa2_set_loopback(struct address_info* hw_config, int loopback){ if(loopback >= 0 && loopback <= 1) { unsigned char misc; opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &misc); misc = (misc & 0xef) | ((loopback & 1) << 4); opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc); } else { printk(KERN_ERR "opl3sa2: not setting loopback, it must be either 0 or 1\n"); }}static void __exit unload_opl3sa2(struct address_info* hw_config, int card){ /* Release control ports */ release_region(hw_config->io_base, 2); /* Unload mixer */ if(opl3sa2_mixer[card] >= 0) sound_unload_mixerdev(opl3sa2_mixer[card]);}#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULEstruct isapnp_device_id isapnp_opl3sa2_list[] __initdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), 0 }, {0}};MODULE_DEVICE_TABLE(isapnp, isapnp_opl3sa2_list);static int __init opl3sa2_isapnp_probe(struct address_info* hw_cfg, struct address_info* mss_cfg, struct address_info* mpu_cfg, int card){ static struct pci_dev* dev; int ret; /* Find and configure device */ dev = isapnp_find_dev(NULL, ISAPNP_VENDOR('Y','M','H'), ISAPNP_FUNCTION(0x0021), dev); if(dev == NULL) { return -ENODEV; } /* * If device is active, assume configured with /proc/isapnp * and use anyway. Any other way to check this? */ ret = dev->prepare(dev); if(ret && ret != -EBUSY) { printk(KERN_ERR "opl3sa2: ISA PnP found device that could not be autoconfigured.\n"); return -ENODEV; } if(ret == -EBUSY) { opl3sa2_activated[card] = 1; } else { if(dev->activate(dev) < 0) { printk(KERN_WARNING "opl3sa2: ISA PnP activate failed\n"); opl3sa2_activated[card] = 0; return -ENODEV; } printk(KERN_DEBUG "opl3sa2: Activated ISA PnP card %d (active=%d)\n", card, dev->active); } /* Our own config: */ hw_cfg->io_base = dev->resource[4].start; hw_cfg->irq = dev->irq_resource[0].start; hw_cfg->dma = dev->dma_resource[0].start; hw_cfg->dma2 = dev->dma_resource[1].start; /* The MSS config: */ mss_cfg->io_base = dev->resource[1].start; mss_cfg->irq = dev->irq_resource[0].start; mss_cfg->dma = dev->dma_resource[0].start; mss_cfg->dma2 = dev->dma_resource[1].start; mss_cfg->card_subtype = 1; /* No IRQ or DMA setup */ mpu_cfg->io_base = dev->resource[3].start; mpu_cfg->irq = dev->irq_resource[0].start; mpu_cfg->dma = -1; mpu_cfg->dma2 = -1; mpu_cfg->always_detect = 1; /* It's there, so use shared IRQs */ /* Call me paranoid: */ opl3sa2_clear_slots(hw_cfg); opl3sa2_clear_slots(mss_cfg); opl3sa2_clear_slots(mpu_cfg); opl3sa2_dev[card] = dev; return 0;}#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE *//* End of component functions *//* Power Management support functions */static int opl3sa2_suspend(struct pm_dev *pdev, unsigned char pm_mode){ unsigned long flags; opl3sa2_mixerdata *p; if (!pdev) return -EINVAL; save_flags(flags); cli(); p = (opl3sa2_mixerdata *) pdev->data; switch (pm_mode) { case 1: pm_mode = OPL3SA2_PM_MODE1; break; case 2: pm_mode = OPL3SA2_PM_MODE2; break; case 3: pm_mode = OPL3SA2_PM_MODE3; break; default: /* we don't know howto handle this... */ restore_flags(flags); return -EBUSY; } p->in_suspend = 1; /* its supposed to automute before suspending, so we wont bother */ opl3sa2_read(p->cfg_port, OPL3SA2_PM, &p->pm_reg); opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->pm_reg | pm_mode); /* wait a while for the clock oscillator to stabilise */ mdelay(10); restore_flags(flags); return 0;}static int opl3sa2_resume(struct pm_dev *pdev){ unsigned long flags; opl3sa2_mixerdata *p; if (!pdev) return -EINVAL; p = (opl3sa2_mixerdata *) pdev->data; save_flags(flags); cli(); /* I don't think this is necessary */ opl3sa2_write(p->cfg_port, OPL3SA2_PM, p->pm_reg); opl3sa2_mixer_restore(p, p->card); p->in_suspend = 0; restore_flags(flags); return 0;}static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data){ unsigned char mode = (unsigned char)data; switch (rqst) { case PM_SUSPEND: return opl3sa2_suspend(pdev, mode); case PM_RESUME: return opl3sa2_resume(pdev); } return 0;}/* * Install OPL3-SA2 based card(s). * * Need to have ad1848 and mpu401 loaded ready. */static int __init init_opl3sa2(void){ int card; int max; /* Sanitize isapnp and multiple settings */ isapnp = isapnp != 0 ? 1 : 0; multiple = multiple != 0 ? 1 : 0; max = (multiple && isapnp) ? OPL3SA2_CARDS_MAX : 1; for(card = 0; card < max; card++, opl3sa2_cards_num++) {#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE /* * Please remember that even with CONFIG_ISAPNP defined one * should still be able to disable PNP support for this * single driver! */ if(isapnp && opl3sa2_isapnp_probe(&cfg[card], &cfg_mss[card], &cfg_mpu[card], card) < 0) { if(!opl3sa2_cards_num) printk(KERN_INFO "opl3sa2: No PnP cards found\n"); if(io == -1) break; isapnp=0; printk(KERN_INFO "opl3sa2: Search for a card at 0x%d.\n", io); /* Fall through */ }#endif /* If a user wants an I/O then assume they meant it */ if(!isapnp) { if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) { printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set\n"); return -EINVAL; } /* * Our own config: * (NOTE: IRQ and DMA aren't used, so they're set to * give pretty output from conf_printf. :) */ cfg[card].io_base = io; cfg[card].irq = irq; cfg[card].dma = dma; cfg[card].dma2 = dma2; /* The MSS config: */ cfg_mss[card].io_base = mss_io; cfg_mss[card].irq = irq; cfg_mss[card].dma = dma; cfg_mss[card].dma2 = dma2; cfg_mss[card].card_subtype = 1; /* No IRQ or DMA setup */ cfg_mpu[card].io_base = mpu_io; cfg_mpu[card].irq = irq; cfg_mpu[card].dma = -1; cfg_mpu[card].always_detect = 1; /* Use shared IRQs */ /* Call me paranoid: */ opl3sa2_clear_slots(&cfg[card]); opl3sa2_clear_slots(&cfg_mss[card]); opl3sa2_clear_slots(&cfg_mpu[card]); } if(!probe_opl3sa2(&cfg[card], card) || !probe_opl3sa2_mss(&cfg_mss[card])) { /* * If one or more cards are already registered, don't * return an error but print a warning. Note, this * should never really happen unless the hardware or * ISA PnP screwed up. */ if(opl3sa2_cards_num) { printk(KERN_WARNING "opl3sa2: There was a problem probing one " " of the ISA PNP cards, continuing\n"); opl3sa2_cards_num--; continue; } else return -ENODEV; } attach_opl3sa2(&cfg[card], card); conf_printf(chipset_name[card], &cfg[card]); attach_opl3sa2_mss(&cfg_mss[card]); attach_opl3sa2_mixer(&cfg[card], card); opl3sa2_data[card].card = card; /* register our power management capabilities */ opl3sa2_data[card].pmdev = pm_register(PM_ISA_DEV, card, opl3sa2_pm_callback); if (opl3sa2_data[card].pmdev) opl3sa2_data[card].pmdev->data = &opl3sa2_data[card]; /* * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and * it's supported. */ if(ymode != -1) { if(chipset[card] == CHIPSET_OPL3SA2) { printk(KERN_ERR "opl3sa2: ymode not supported on OPL3-SA2\n"); } else { opl3sa2_set_ymode(&cfg[card], ymode); } } /* Set A/D input to Mono loopback if asked to. */ if(loopback != -1) { opl3sa2_set_loopback(&cfg[card], loopback); } /* Attach MPU if we've been asked to do so */ if(cfg_mpu[card].io_base != -1) { if(probe_opl3sa2_mpu(&cfg_mpu[card])) { attach_opl3sa2_mpu(&cfg_mpu[card]); } } } if(isapnp) { printk(KERN_NOTICE "opl3sa2: %d PnP card(s) found.\n", opl3sa2_cards_num); } return 0;}/* * Uninstall OPL3-SA2 based card(s). */static void __exit cleanup_opl3sa2(void){ int card; for(card = 0; card < opl3sa2_cards_num; card++) { if (opl3sa2_data[card].pmdev) pm_unregister(opl3sa2_data[card].pmdev); if(cfg_mpu[card].slots[1] != -1) { unload_opl3sa2_mpu(&cfg_mpu[card]); } unload_opl3sa2_mss(&cfg_mss[card]); unload_opl3sa2(&cfg[card], card);#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE if(opl3sa2_activated[card] && opl3sa2_dev[card]) { opl3sa2_dev[card]->deactivate(opl3sa2_dev[card]); printk(KERN_DEBUG "opl3sa2: Deactivated ISA PnP card %d (active=%d)\n", card, opl3sa2_dev[card]->active); }#endif }}module_init(init_opl3sa2);module_exit(cleanup_opl3sa2);#ifndef MODULEstatic int __init setup_opl3sa2(char *str){ /* io, irq, dma, dma2,... */#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE int ints[11];#else int ints[9];#endif str = get_options(str, ARRAY_SIZE(ints), ints); io = ints[1]; irq = ints[2]; dma = ints[3]; dma2 = ints[4]; mss_io = ints[5]; mpu_io = ints[6]; ymode = ints[7]; loopback = ints[8];#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE isapnp = ints[9]; multiple = ints[10];#endif return 1;}__setup("opl3sa2=", setup_opl3sa2);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -