📄 via82xx.c
字号:
}, { .subvendor = 0x1019, .subdevice = 0x0a85, .name = "ECS L7VMM2", .type = AC97_TUNE_HP_ONLY }, { .subvendor = 0x1849, .subdevice = 0x3059, .name = "ASRock K7VM2", .type = AC97_TUNE_HP_ONLY /* VT1616 */ }, { .subvendor = 0x14cd, .subdevice = 0x7002, .name = "Unknown", .type = AC97_TUNE_ALC_JACK }, { .subvendor = 0x1071, .subdevice = 0x8590, .name = "Mitac Mobo", .type = AC97_TUNE_ALC_JACK }, { .subvendor = 0x161f, .subdevice = 0x202b, .name = "Arima Notebook", .type = AC97_TUNE_HP_ONLY, }, { .subvendor = 0x161f, .subdevice = 0x2032, .name = "Targa Traveller 811", .type = AC97_TUNE_HP_ONLY, }, { .subvendor = 0x161f, .subdevice = 0x2032, .name = "m680x", .type = AC97_TUNE_HP_ONLY, /* http://launchpad.net/bugs/38546 */ }, { } /* terminator */};static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_override){ struct snd_ac97_template ac97; int err; static struct snd_ac97_bus_ops ops = { .write = snd_via82xx_codec_write, .read = snd_via82xx_codec_read, .wait = snd_via82xx_codec_wait, }; if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus)) < 0) return err; chip->ac97_bus->private_free = snd_via82xx_mixer_free_ac97_bus; chip->ac97_bus->clock = chip->ac97_clock; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.private_free = snd_via82xx_mixer_free_ac97; ac97.pci = chip->pci; ac97.scaps = AC97_SCAP_SKIP_MODEM | AC97_SCAP_POWER_SAVE; if ((err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97)) < 0) return err; snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override); if (chip->chip_type != TYPE_VIA686) { /* use slot 10/11 */ snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4); } return 0;}#ifdef SUPPORT_JOYSTICK#define JOYSTICK_ADDR 0x200static int __devinit snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy){ struct gameport *gp; struct resource *r; if (!joystick) return -ENODEV; r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport"); if (!r) { printk(KERN_WARNING "via82xx: cannot reserve joystick port 0x%#x\n", JOYSTICK_ADDR); return -EBUSY; } chip->gameport = gp = gameport_allocate_port(); if (!gp) { printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } gameport_set_name(gp, "VIA686 Gameport"); gameport_set_phys(gp, "pci%s/gameport0", pci_name(chip->pci)); gameport_set_dev_parent(gp, &chip->pci->dev); gp->io = JOYSTICK_ADDR; gameport_set_port_data(gp, r); /* Enable legacy joystick port */ *legacy |= VIA_FUNC_ENABLE_GAME; pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, *legacy); gameport_register_port(chip->gameport); return 0;}static void snd_via686_free_gameport(struct via82xx *chip){ if (chip->gameport) { struct resource *r = gameport_get_port_data(chip->gameport); gameport_unregister_port(chip->gameport); chip->gameport = NULL; release_and_free_resource(r); }}#elsestatic inline int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy){ return -ENOSYS;}static inline void snd_via686_free_gameport(struct via82xx *chip) { }#endif/* * */static int __devinit snd_via8233_init_misc(struct via82xx *chip){ int i, err, caps; unsigned char val; caps = chip->chip_type == TYPE_VIA8233A ? 1 : 2; for (i = 0; i < caps; i++) { snd_via8233_capture_source.index = i; err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_capture_source, chip)); if (err < 0) return err; } if (ac97_can_spdif(chip->ac97)) { err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs3_spdif_control, chip)); if (err < 0) return err; } if (chip->chip_type != TYPE_VIA8233A) { /* when no h/w PCM volume control is found, use DXS volume control * as the PCM vol control */ struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); strcpy(sid.name, "PCM Playback Volume"); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; if (! snd_ctl_find_id(chip->card, &sid)) { snd_printd(KERN_INFO "Using DXS as PCM Playback\n"); err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip)); if (err < 0) return err; } else /* Using DXS when PCM emulation is enabled is really weird */ { /* Standalone DXS controls */ err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip)); if (err < 0) return err; } } /* select spdif data slot 10/11 */ pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &val); val = (val & ~VIA8233_SPDIF_SLOT_MASK) | VIA8233_SPDIF_SLOT_1011; val &= ~VIA8233_SPDIF_DX3; /* SPDIF off as default */ pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, val); return 0;}static int __devinit snd_via686_init_misc(struct via82xx *chip){ unsigned char legacy, legacy_cfg; int rev_h = 0; legacy = chip->old_legacy; legacy_cfg = chip->old_legacy_cfg; legacy |= VIA_FUNC_MIDI_IRQMASK; /* FIXME: correct? (disable MIDI) */ legacy &= ~VIA_FUNC_ENABLE_GAME; /* disable joystick */ if (chip->revision >= VIA_REV_686_H) { rev_h = 1; if (mpu_port >= 0x200) { /* force MIDI */ mpu_port &= 0xfffc; pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);#ifdef CONFIG_PM chip->mpu_port_saved = mpu_port;#endif } else { mpu_port = pci_resource_start(chip->pci, 2); } } else { switch (mpu_port) { /* force MIDI */ case 0x300: case 0x310: case 0x320: case 0x330: legacy_cfg &= ~(3 << 2); legacy_cfg |= (mpu_port & 0x0030) >> 2; break; default: /* no, use BIOS settings */ if (legacy & VIA_FUNC_ENABLE_MIDI) mpu_port = 0x300 + ((legacy_cfg & 0x000c) << 2); break; } } if (mpu_port >= 0x200 && (chip->mpu_res = request_region(mpu_port, 2, "VIA82xx MPU401")) != NULL) { if (rev_h) legacy |= VIA_FUNC_MIDI_PNP; /* enable PCI I/O 2 */ legacy |= VIA_FUNC_ENABLE_MIDI; } else { if (rev_h) legacy &= ~VIA_FUNC_MIDI_PNP; /* disable PCI I/O 2 */ legacy &= ~VIA_FUNC_ENABLE_MIDI; mpu_port = 0; } pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); pci_write_config_byte(chip->pci, VIA_PNP_CONTROL, legacy_cfg); if (chip->mpu_res) { if (snd_mpu401_uart_new(chip->card, 0, MPU401_HW_VIA686A, mpu_port, MPU401_INFO_INTEGRATED, chip->irq, 0, &chip->rmidi) < 0) { printk(KERN_WARNING "unable to initialize MPU-401" " at 0x%lx, skipping\n", mpu_port); legacy &= ~VIA_FUNC_ENABLE_MIDI; } else { legacy &= ~VIA_FUNC_MIDI_IRQMASK; /* enable MIDI interrupt */ } pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, legacy); } snd_via686_create_gameport(chip, &legacy);#ifdef CONFIG_PM chip->legacy_saved = legacy; chip->legacy_cfg_saved = legacy_cfg;#endif return 0;}/* * proc interface */static void snd_via82xx_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer){ struct via82xx *chip = entry->private_data; int i; snd_iprintf(buffer, "%s\n\n", chip->card->longname); for (i = 0; i < 0xa0; i += 4) { snd_iprintf(buffer, "%02x: %08x\n", i, inl(chip->port + i)); }}static void __devinit snd_via82xx_proc_init(struct via82xx *chip){ struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "via82xx", &entry)) snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read);}/* * */static int snd_via82xx_chip_init(struct via82xx *chip){ unsigned int val; unsigned long end_time; unsigned char pval;#if 0 /* broken on K7M? */ if (chip->chip_type == TYPE_VIA686) /* disable all legacy ports */ pci_write_config_byte(chip->pci, VIA_FUNC_ENABLE, 0);#endif pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (! (pval & VIA_ACLINK_C00_READY)) { /* codec not ready? */ /* deassert ACLink reset, force SYNC */ pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_ENABLE | VIA_ACLINK_CTRL_RESET | VIA_ACLINK_CTRL_SYNC); udelay(100);#if 1 /* FIXME: should we do full reset here for all chip models? */ pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, 0x00); udelay(100);#else /* deassert ACLink reset, force SYNC (warm AC'97 reset) */ pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_RESET|VIA_ACLINK_CTRL_SYNC); udelay(2);#endif /* ACLink on, deassert ACLink reset, VSR, SGD data out */ /* note - FM data out has trouble with non VRA codecs !! */ pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT); udelay(100); } /* Make sure VRA is enabled, in case we didn't do a * complete codec reset, above */ pci_read_config_byte(chip->pci, VIA_ACLINK_CTRL, &pval); if ((pval & VIA_ACLINK_CTRL_INIT) != VIA_ACLINK_CTRL_INIT) { /* ACLink on, deassert ACLink reset, VSR, SGD data out */ /* note - FM data out has trouble with non VRA codecs !! */ pci_write_config_byte(chip->pci, VIA_ACLINK_CTRL, VIA_ACLINK_CTRL_INIT); udelay(100); } /* wait until codec ready */ end_time = jiffies + msecs_to_jiffies(750); do { pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval); if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */ break; schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val);#if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */ snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ | VIA_REG_AC97_SECONDARY_VALID | (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT)); end_time = jiffies + msecs_to_jiffies(750); snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ | VIA_REG_AC97_SECONDARY_VALID | (VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT)); do { if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) { chip->ac97_secondary = 1; goto __ac97_ok2; } schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); /* This is ok, the most of motherboards have only one codec */ __ac97_ok2:#endif if (chip->chip_type == TYPE_VIA686) { /* route FM trap to IRQ, disable FM trap */ pci_write_config_byte(chip->pci, VIA_FM_NMI_CTRL, 0); /* disable all GPI interrupts */ outl(0, VIAREG(chip, GPI_INTR)); } if (chip->chip_type != TYPE_VIA686) { /* Workaround for Award BIOS bug: * DXS channels don't work properly with VRA if MC97 is disabled. */ struct pci_dev *pci; pci = pci_get_device(0x1106, 0x3068, NULL); /* MC97 */ if (pci) { unsigned char data; pci_read_config_byte(pci, 0x44, &data); pci_write_config_byte(pci, 0x44, data | 0x40); pci_dev_put(pci); } } if (chip->chip_type != TYPE_VIA8233A) { int i, idx; for (idx = 0; idx < 4; idx++) { unsigned long port = chip->port + 0x10 * idx; for (i = 0; i < 2; i++) { chip->playback_volume[idx][i]=chip->playback_volume_c[i]; outb(chip->playback_volume_c[i], port + VIA_REG_OFS_PLAYBACK_VOLUME_L + i); } } } return 0;}#ifdef CONFIG_PM/* * power management */static int snd_via82xx_suspend(struct pci_dev *pci, pm_message_t state){ struct snd_card *card = pci_get_drvdata(pci); struct via82xx *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < 2; i++) snd_pcm_suspend_all(chip->pcms[i]); for (i = 0; i < chip->num_devs; i++) snd_via82xx_channel_reset(chip, &chip->devs[i]); synchronize_irq(chip->irq); snd_ac97_suspend(chip->ac97); /* save misc values */ if (chip->chip_type != TYPE_VIA686) { pci_read_config_byte(chip->pci, VIA8233_SPDIF_CTRL, &chip->spdif_ctrl_saved); chip->capture_src_saved[0] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL); chip->capture_src_saved[1] = inb(chip->port + VIA_REG_CAPTURE_CHANNEL + 0x10); } pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0;}static int snd_via82xx_resume(struct pci_dev *p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -