162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 462306a36Sopenharmony_ci * Routines for control of YMF724/740/744/754 chips 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/firmware.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/sched.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/mutex.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/io.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <sound/core.h> 1962306a36Sopenharmony_ci#include <sound/control.h> 2062306a36Sopenharmony_ci#include <sound/info.h> 2162306a36Sopenharmony_ci#include <sound/tlv.h> 2262306a36Sopenharmony_ci#include "ymfpci.h" 2362306a36Sopenharmony_ci#include <sound/asoundef.h> 2462306a36Sopenharmony_ci#include <sound/mpu401.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <asm/byteorder.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * common I/O routines 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic void snd_ymfpci_irq_wait(struct snd_ymfpci *chip); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic inline void snd_ymfpci_writeb(struct snd_ymfpci *chip, u32 offset, u8 val) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci writeb(val, chip->reg_area_virt + offset); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline u16 snd_ymfpci_readw(struct snd_ymfpci *chip, u32 offset) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return readw(chip->reg_area_virt + offset); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic inline void snd_ymfpci_writew(struct snd_ymfpci *chip, u32 offset, u16 val) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci writew(val, chip->reg_area_virt + offset); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline u32 snd_ymfpci_readl(struct snd_ymfpci *chip, u32 offset) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return readl(chip->reg_area_virt + offset); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic inline void snd_ymfpci_writel(struct snd_ymfpci *chip, u32 offset, u32 val) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci writel(val, chip->reg_area_virt + offset); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci unsigned long end_time; 6262306a36Sopenharmony_ci u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci end_time = jiffies + msecs_to_jiffies(750); 6562306a36Sopenharmony_ci do { 6662306a36Sopenharmony_ci if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0) 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci schedule_timeout_uninterruptible(1); 6962306a36Sopenharmony_ci } while (time_before(jiffies, end_time)); 7062306a36Sopenharmony_ci dev_err(chip->card->dev, 7162306a36Sopenharmony_ci "codec_ready: codec %i is not ready [0x%x]\n", 7262306a36Sopenharmony_ci secondary, snd_ymfpci_readw(chip, reg)); 7362306a36Sopenharmony_ci return -EBUSY; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic void snd_ymfpci_codec_write(struct snd_ac97 *ac97, u16 reg, u16 val) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct snd_ymfpci *chip = ac97->private_data; 7962306a36Sopenharmony_ci u32 cmd; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci snd_ymfpci_codec_ready(chip, 0); 8262306a36Sopenharmony_ci cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val; 8362306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_AC97CMDDATA, cmd); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic u16 snd_ymfpci_codec_read(struct snd_ac97 *ac97, u16 reg) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct snd_ymfpci *chip = ac97->private_data; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (snd_ymfpci_codec_ready(chip, 0)) 9162306a36Sopenharmony_ci return ~0; 9262306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg); 9362306a36Sopenharmony_ci if (snd_ymfpci_codec_ready(chip, 0)) 9462306a36Sopenharmony_ci return ~0; 9562306a36Sopenharmony_ci if (chip->device_id == PCI_DEVICE_ID_YAMAHA_744 && chip->rev < 2) { 9662306a36Sopenharmony_ci int i; 9762306a36Sopenharmony_ci for (i = 0; i < 600; i++) 9862306a36Sopenharmony_ci snd_ymfpci_readw(chip, YDSXGR_PRISTATUSDATA); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci return snd_ymfpci_readw(chip, YDSXGR_PRISTATUSDATA); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Misc routines 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic u32 snd_ymfpci_calc_delta(u32 rate) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci switch (rate) { 11062306a36Sopenharmony_ci case 8000: return 0x02aaab00; 11162306a36Sopenharmony_ci case 11025: return 0x03accd00; 11262306a36Sopenharmony_ci case 16000: return 0x05555500; 11362306a36Sopenharmony_ci case 22050: return 0x07599a00; 11462306a36Sopenharmony_ci case 32000: return 0x0aaaab00; 11562306a36Sopenharmony_ci case 44100: return 0x0eb33300; 11662306a36Sopenharmony_ci default: return ((rate << 16) / 375) << 5; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic const u32 def_rate[8] = { 12162306a36Sopenharmony_ci 100, 2000, 8000, 11025, 16000, 22050, 32000, 48000 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic u32 snd_ymfpci_calc_lpfK(u32 rate) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci u32 i; 12762306a36Sopenharmony_ci static const u32 val[8] = { 12862306a36Sopenharmony_ci 0x00570000, 0x06AA0000, 0x18B20000, 0x20930000, 12962306a36Sopenharmony_ci 0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000 13062306a36Sopenharmony_ci }; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (rate == 44100) 13362306a36Sopenharmony_ci return 0x40000000; /* FIXME: What's the right value? */ 13462306a36Sopenharmony_ci for (i = 0; i < 8; i++) 13562306a36Sopenharmony_ci if (rate <= def_rate[i]) 13662306a36Sopenharmony_ci return val[i]; 13762306a36Sopenharmony_ci return val[0]; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic u32 snd_ymfpci_calc_lpfQ(u32 rate) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci u32 i; 14362306a36Sopenharmony_ci static const u32 val[8] = { 14462306a36Sopenharmony_ci 0x35280000, 0x34A70000, 0x32020000, 0x31770000, 14562306a36Sopenharmony_ci 0x31390000, 0x31C90000, 0x33D00000, 0x40000000 14662306a36Sopenharmony_ci }; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (rate == 44100) 14962306a36Sopenharmony_ci return 0x370A0000; 15062306a36Sopenharmony_ci for (i = 0; i < 8; i++) 15162306a36Sopenharmony_ci if (rate <= def_rate[i]) 15262306a36Sopenharmony_ci return val[i]; 15362306a36Sopenharmony_ci return val[0]; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * Hardware start management 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void snd_ymfpci_hw_start(struct snd_ymfpci *chip) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci unsigned long flags; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 16562306a36Sopenharmony_ci if (chip->start_count++ > 0) 16662306a36Sopenharmony_ci goto __end; 16762306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, 16862306a36Sopenharmony_ci snd_ymfpci_readl(chip, YDSXGR_MODE) | 3); 16962306a36Sopenharmony_ci chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1; 17062306a36Sopenharmony_ci __end: 17162306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void snd_ymfpci_hw_stop(struct snd_ymfpci *chip) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci unsigned long flags; 17762306a36Sopenharmony_ci long timeout = 1000; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 18062306a36Sopenharmony_ci if (--chip->start_count > 0) 18162306a36Sopenharmony_ci goto __end; 18262306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, 18362306a36Sopenharmony_ci snd_ymfpci_readl(chip, YDSXGR_MODE) & ~3); 18462306a36Sopenharmony_ci while (timeout-- > 0) { 18562306a36Sopenharmony_ci if ((snd_ymfpci_readl(chip, YDSXGR_STATUS) & 2) == 0) 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci if (atomic_read(&chip->interrupt_sleep_count)) { 18962306a36Sopenharmony_ci atomic_set(&chip->interrupt_sleep_count, 0); 19062306a36Sopenharmony_ci wake_up(&chip->interrupt_sleep); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci __end: 19362306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci/* 19762306a36Sopenharmony_ci * Playback voice management 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic int voice_alloc(struct snd_ymfpci *chip, 20162306a36Sopenharmony_ci enum snd_ymfpci_voice_type type, int pair, 20262306a36Sopenharmony_ci struct snd_ymfpci_voice **rvoice) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct snd_ymfpci_voice *voice, *voice2; 20562306a36Sopenharmony_ci int idx; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci *rvoice = NULL; 20862306a36Sopenharmony_ci for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) { 20962306a36Sopenharmony_ci voice = &chip->voices[idx]; 21062306a36Sopenharmony_ci voice2 = pair ? &chip->voices[idx+1] : NULL; 21162306a36Sopenharmony_ci if (voice->use || (voice2 && voice2->use)) 21262306a36Sopenharmony_ci continue; 21362306a36Sopenharmony_ci voice->use = 1; 21462306a36Sopenharmony_ci if (voice2) 21562306a36Sopenharmony_ci voice2->use = 1; 21662306a36Sopenharmony_ci switch (type) { 21762306a36Sopenharmony_ci case YMFPCI_PCM: 21862306a36Sopenharmony_ci voice->pcm = 1; 21962306a36Sopenharmony_ci if (voice2) 22062306a36Sopenharmony_ci voice2->pcm = 1; 22162306a36Sopenharmony_ci break; 22262306a36Sopenharmony_ci case YMFPCI_SYNTH: 22362306a36Sopenharmony_ci voice->synth = 1; 22462306a36Sopenharmony_ci break; 22562306a36Sopenharmony_ci case YMFPCI_MIDI: 22662306a36Sopenharmony_ci voice->midi = 1; 22762306a36Sopenharmony_ci break; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci snd_ymfpci_hw_start(chip); 23062306a36Sopenharmony_ci if (voice2) 23162306a36Sopenharmony_ci snd_ymfpci_hw_start(chip); 23262306a36Sopenharmony_ci *rvoice = voice; 23362306a36Sopenharmony_ci return 0; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci return -ENOMEM; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int snd_ymfpci_voice_alloc(struct snd_ymfpci *chip, 23962306a36Sopenharmony_ci enum snd_ymfpci_voice_type type, int pair, 24062306a36Sopenharmony_ci struct snd_ymfpci_voice **rvoice) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci unsigned long flags; 24362306a36Sopenharmony_ci int result; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (snd_BUG_ON(!rvoice)) 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci if (snd_BUG_ON(pair && type != YMFPCI_PCM)) 24862306a36Sopenharmony_ci return -EINVAL; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci spin_lock_irqsave(&chip->voice_lock, flags); 25162306a36Sopenharmony_ci for (;;) { 25262306a36Sopenharmony_ci result = voice_alloc(chip, type, pair, rvoice); 25362306a36Sopenharmony_ci if (result == 0 || type != YMFPCI_PCM) 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci /* TODO: synth/midi voice deallocation */ 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->voice_lock, flags); 25962306a36Sopenharmony_ci return result; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int snd_ymfpci_voice_free(struct snd_ymfpci *chip, struct snd_ymfpci_voice *pvoice) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci unsigned long flags; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (snd_BUG_ON(!pvoice)) 26762306a36Sopenharmony_ci return -EINVAL; 26862306a36Sopenharmony_ci snd_ymfpci_hw_stop(chip); 26962306a36Sopenharmony_ci spin_lock_irqsave(&chip->voice_lock, flags); 27062306a36Sopenharmony_ci if (pvoice->number == chip->src441_used) { 27162306a36Sopenharmony_ci chip->src441_used = -1; 27262306a36Sopenharmony_ci pvoice->ypcm->use_441_slot = 0; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0; 27562306a36Sopenharmony_ci pvoice->ypcm = NULL; 27662306a36Sopenharmony_ci pvoice->interrupt = NULL; 27762306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->voice_lock, flags); 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* 28262306a36Sopenharmony_ci * PCM part 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_voice *voice) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 28862306a36Sopenharmony_ci u32 pos, delta; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ypcm = voice->ypcm; 29162306a36Sopenharmony_ci if (!ypcm) 29262306a36Sopenharmony_ci return; 29362306a36Sopenharmony_ci if (ypcm->substream == NULL) 29462306a36Sopenharmony_ci return; 29562306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 29662306a36Sopenharmony_ci if (ypcm->running) { 29762306a36Sopenharmony_ci pos = le32_to_cpu(voice->bank[chip->active_bank].start); 29862306a36Sopenharmony_ci if (pos < ypcm->last_pos) 29962306a36Sopenharmony_ci delta = pos + (ypcm->buffer_size - ypcm->last_pos); 30062306a36Sopenharmony_ci else 30162306a36Sopenharmony_ci delta = pos - ypcm->last_pos; 30262306a36Sopenharmony_ci ypcm->period_pos += delta; 30362306a36Sopenharmony_ci ypcm->last_pos = pos; 30462306a36Sopenharmony_ci if (ypcm->period_pos >= ypcm->period_size) { 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci dev_dbg(chip->card->dev, 30762306a36Sopenharmony_ci "done - active_bank = 0x%x, start = 0x%x\n", 30862306a36Sopenharmony_ci chip->active_bank, 30962306a36Sopenharmony_ci voice->bank[chip->active_bank].start); 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci ypcm->period_pos %= ypcm->period_size; 31262306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 31362306a36Sopenharmony_ci snd_pcm_period_elapsed(ypcm->substream); 31462306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (unlikely(ypcm->update_pcm_vol)) { 31862306a36Sopenharmony_ci unsigned int subs = ypcm->substream->number; 31962306a36Sopenharmony_ci unsigned int next_bank = 1 - chip->active_bank; 32062306a36Sopenharmony_ci struct snd_ymfpci_playback_bank *bank; 32162306a36Sopenharmony_ci __le32 volume; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci bank = &voice->bank[next_bank]; 32462306a36Sopenharmony_ci volume = cpu_to_le32(chip->pcm_mixer[subs].left << 15); 32562306a36Sopenharmony_ci bank->left_gain_end = volume; 32662306a36Sopenharmony_ci if (ypcm->output_rear) 32762306a36Sopenharmony_ci bank->eff2_gain_end = volume; 32862306a36Sopenharmony_ci if (ypcm->voices[1]) 32962306a36Sopenharmony_ci bank = &ypcm->voices[1]->bank[next_bank]; 33062306a36Sopenharmony_ci volume = cpu_to_le32(chip->pcm_mixer[subs].right << 15); 33162306a36Sopenharmony_ci bank->right_gain_end = volume; 33262306a36Sopenharmony_ci if (ypcm->output_rear) 33362306a36Sopenharmony_ci bank->eff3_gain_end = volume; 33462306a36Sopenharmony_ci ypcm->update_pcm_vol--; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 34362306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 34462306a36Sopenharmony_ci struct snd_ymfpci *chip = ypcm->chip; 34562306a36Sopenharmony_ci u32 pos, delta; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 34862306a36Sopenharmony_ci if (ypcm->running) { 34962306a36Sopenharmony_ci pos = le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift; 35062306a36Sopenharmony_ci if (pos < ypcm->last_pos) 35162306a36Sopenharmony_ci delta = pos + (ypcm->buffer_size - ypcm->last_pos); 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci delta = pos - ypcm->last_pos; 35462306a36Sopenharmony_ci ypcm->period_pos += delta; 35562306a36Sopenharmony_ci ypcm->last_pos = pos; 35662306a36Sopenharmony_ci if (ypcm->period_pos >= ypcm->period_size) { 35762306a36Sopenharmony_ci ypcm->period_pos %= ypcm->period_size; 35862306a36Sopenharmony_ci /* 35962306a36Sopenharmony_ci dev_dbg(chip->card->dev, 36062306a36Sopenharmony_ci "done - active_bank = 0x%x, start = 0x%x\n", 36162306a36Sopenharmony_ci chip->active_bank, 36262306a36Sopenharmony_ci voice->bank[chip->active_bank].start); 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 36562306a36Sopenharmony_ci snd_pcm_period_elapsed(substream); 36662306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic int snd_ymfpci_playback_trigger(struct snd_pcm_substream *substream, 37362306a36Sopenharmony_ci int cmd) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 37662306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; 37762306a36Sopenharmony_ci struct snd_kcontrol *kctl = NULL; 37862306a36Sopenharmony_ci int result = 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 38162306a36Sopenharmony_ci if (ypcm->voices[0] == NULL) { 38262306a36Sopenharmony_ci result = -EINVAL; 38362306a36Sopenharmony_ci goto __unlock; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci switch (cmd) { 38662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 38762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 38862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 38962306a36Sopenharmony_ci chip->ctrl_playback[ypcm->voices[0]->number + 1] = cpu_to_le32(ypcm->voices[0]->bank_addr); 39062306a36Sopenharmony_ci if (ypcm->voices[1] != NULL && !ypcm->use_441_slot) 39162306a36Sopenharmony_ci chip->ctrl_playback[ypcm->voices[1]->number + 1] = cpu_to_le32(ypcm->voices[1]->bank_addr); 39262306a36Sopenharmony_ci ypcm->running = 1; 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 39562306a36Sopenharmony_ci if (substream->pcm == chip->pcm && !ypcm->use_441_slot) { 39662306a36Sopenharmony_ci kctl = chip->pcm_mixer[substream->number].ctl; 39762306a36Sopenharmony_ci kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci fallthrough; 40062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 40162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 40262306a36Sopenharmony_ci chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0; 40362306a36Sopenharmony_ci if (ypcm->voices[1] != NULL && !ypcm->use_441_slot) 40462306a36Sopenharmony_ci chip->ctrl_playback[ypcm->voices[1]->number + 1] = 0; 40562306a36Sopenharmony_ci ypcm->running = 0; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci default: 40862306a36Sopenharmony_ci result = -EINVAL; 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci __unlock: 41262306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 41362306a36Sopenharmony_ci if (kctl) 41462306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); 41562306a36Sopenharmony_ci return result; 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_cistatic int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream, 41862306a36Sopenharmony_ci int cmd) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 42162306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; 42262306a36Sopenharmony_ci int result = 0; 42362306a36Sopenharmony_ci u32 tmp; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 42662306a36Sopenharmony_ci switch (cmd) { 42762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 42862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 42962306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 43062306a36Sopenharmony_ci tmp = snd_ymfpci_readl(chip, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number); 43162306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, tmp); 43262306a36Sopenharmony_ci ypcm->running = 1; 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 43562306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 43662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 43762306a36Sopenharmony_ci tmp = snd_ymfpci_readl(chip, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number); 43862306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, tmp); 43962306a36Sopenharmony_ci ypcm->running = 0; 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci result = -EINVAL; 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 44662306a36Sopenharmony_ci return result; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic int snd_ymfpci_pcm_voice_alloc(struct snd_ymfpci_pcm *ypcm, int voices) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci int err; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (ypcm->voices[1] != NULL && voices < 2) { 45462306a36Sopenharmony_ci snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[1]); 45562306a36Sopenharmony_ci ypcm->voices[1] = NULL; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci if (voices == 1 && ypcm->voices[0] != NULL) 45862306a36Sopenharmony_ci return 0; /* already allocated */ 45962306a36Sopenharmony_ci if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL) 46062306a36Sopenharmony_ci return 0; /* already allocated */ 46162306a36Sopenharmony_ci if (voices > 1) { 46262306a36Sopenharmony_ci if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) { 46362306a36Sopenharmony_ci snd_ymfpci_voice_free(ypcm->chip, ypcm->voices[0]); 46462306a36Sopenharmony_ci ypcm->voices[0] = NULL; 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci err = snd_ymfpci_voice_alloc(ypcm->chip, YMFPCI_PCM, voices > 1, &ypcm->voices[0]); 46862306a36Sopenharmony_ci if (err < 0) 46962306a36Sopenharmony_ci return err; 47062306a36Sopenharmony_ci ypcm->voices[0]->ypcm = ypcm; 47162306a36Sopenharmony_ci ypcm->voices[0]->interrupt = snd_ymfpci_pcm_interrupt; 47262306a36Sopenharmony_ci if (voices > 1) { 47362306a36Sopenharmony_ci ypcm->voices[1] = &ypcm->chip->voices[ypcm->voices[0]->number + 1]; 47462306a36Sopenharmony_ci ypcm->voices[1]->ypcm = ypcm; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci return 0; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int voiceidx, 48062306a36Sopenharmony_ci struct snd_pcm_runtime *runtime, 48162306a36Sopenharmony_ci int has_pcm_volume) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci struct snd_ymfpci_voice *voice = ypcm->voices[voiceidx]; 48462306a36Sopenharmony_ci u32 format; 48562306a36Sopenharmony_ci u32 delta = snd_ymfpci_calc_delta(runtime->rate); 48662306a36Sopenharmony_ci u32 lpfQ = snd_ymfpci_calc_lpfQ(runtime->rate); 48762306a36Sopenharmony_ci u32 lpfK = snd_ymfpci_calc_lpfK(runtime->rate); 48862306a36Sopenharmony_ci struct snd_ymfpci_playback_bank *bank; 48962306a36Sopenharmony_ci unsigned int nbank; 49062306a36Sopenharmony_ci __le32 vol_left, vol_right; 49162306a36Sopenharmony_ci u8 use_left, use_right; 49262306a36Sopenharmony_ci unsigned long flags; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (snd_BUG_ON(!voice)) 49562306a36Sopenharmony_ci return; 49662306a36Sopenharmony_ci if (runtime->channels == 1) { 49762306a36Sopenharmony_ci use_left = 1; 49862306a36Sopenharmony_ci use_right = 1; 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci use_left = (voiceidx & 1) == 0; 50162306a36Sopenharmony_ci use_right = !use_left; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci if (has_pcm_volume) { 50462306a36Sopenharmony_ci vol_left = cpu_to_le32(ypcm->chip->pcm_mixer 50562306a36Sopenharmony_ci [ypcm->substream->number].left << 15); 50662306a36Sopenharmony_ci vol_right = cpu_to_le32(ypcm->chip->pcm_mixer 50762306a36Sopenharmony_ci [ypcm->substream->number].right << 15); 50862306a36Sopenharmony_ci } else { 50962306a36Sopenharmony_ci vol_left = cpu_to_le32(0x40000000); 51062306a36Sopenharmony_ci vol_right = cpu_to_le32(0x40000000); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci spin_lock_irqsave(&ypcm->chip->voice_lock, flags); 51362306a36Sopenharmony_ci format = runtime->channels == 2 ? 0x00010000 : 0; 51462306a36Sopenharmony_ci if (snd_pcm_format_width(runtime->format) == 8) 51562306a36Sopenharmony_ci format |= 0x80000000; 51662306a36Sopenharmony_ci else if (ypcm->chip->device_id == PCI_DEVICE_ID_YAMAHA_754 && 51762306a36Sopenharmony_ci runtime->rate == 44100 && runtime->channels == 2 && 51862306a36Sopenharmony_ci voiceidx == 0 && (ypcm->chip->src441_used == -1 || 51962306a36Sopenharmony_ci ypcm->chip->src441_used == voice->number)) { 52062306a36Sopenharmony_ci ypcm->chip->src441_used = voice->number; 52162306a36Sopenharmony_ci ypcm->use_441_slot = 1; 52262306a36Sopenharmony_ci format |= 0x10000000; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci if (ypcm->chip->src441_used == voice->number && 52562306a36Sopenharmony_ci (format & 0x10000000) == 0) { 52662306a36Sopenharmony_ci ypcm->chip->src441_used = -1; 52762306a36Sopenharmony_ci ypcm->use_441_slot = 0; 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci if (runtime->channels == 2 && (voiceidx & 1) != 0) 53062306a36Sopenharmony_ci format |= 1; 53162306a36Sopenharmony_ci spin_unlock_irqrestore(&ypcm->chip->voice_lock, flags); 53262306a36Sopenharmony_ci for (nbank = 0; nbank < 2; nbank++) { 53362306a36Sopenharmony_ci bank = &voice->bank[nbank]; 53462306a36Sopenharmony_ci memset(bank, 0, sizeof(*bank)); 53562306a36Sopenharmony_ci bank->format = cpu_to_le32(format); 53662306a36Sopenharmony_ci bank->base = cpu_to_le32(runtime->dma_addr); 53762306a36Sopenharmony_ci bank->loop_end = cpu_to_le32(ypcm->buffer_size); 53862306a36Sopenharmony_ci bank->lpfQ = cpu_to_le32(lpfQ); 53962306a36Sopenharmony_ci bank->delta = 54062306a36Sopenharmony_ci bank->delta_end = cpu_to_le32(delta); 54162306a36Sopenharmony_ci bank->lpfK = 54262306a36Sopenharmony_ci bank->lpfK_end = cpu_to_le32(lpfK); 54362306a36Sopenharmony_ci bank->eg_gain = 54462306a36Sopenharmony_ci bank->eg_gain_end = cpu_to_le32(0x40000000); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (ypcm->output_front) { 54762306a36Sopenharmony_ci if (use_left) { 54862306a36Sopenharmony_ci bank->left_gain = 54962306a36Sopenharmony_ci bank->left_gain_end = vol_left; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci if (use_right) { 55262306a36Sopenharmony_ci bank->right_gain = 55362306a36Sopenharmony_ci bank->right_gain_end = vol_right; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci if (ypcm->output_rear) { 55762306a36Sopenharmony_ci if (!ypcm->swap_rear) { 55862306a36Sopenharmony_ci if (use_left) { 55962306a36Sopenharmony_ci bank->eff2_gain = 56062306a36Sopenharmony_ci bank->eff2_gain_end = vol_left; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci if (use_right) { 56362306a36Sopenharmony_ci bank->eff3_gain = 56462306a36Sopenharmony_ci bank->eff3_gain_end = vol_right; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } else { 56762306a36Sopenharmony_ci /* The SPDIF out channels seem to be swapped, so we have 56862306a36Sopenharmony_ci * to swap them here, too. The rear analog out channels 56962306a36Sopenharmony_ci * will be wrong, but otherwise AC3 would not work. 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_ci if (use_left) { 57262306a36Sopenharmony_ci bank->eff3_gain = 57362306a36Sopenharmony_ci bank->eff3_gain_end = vol_left; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci if (use_right) { 57662306a36Sopenharmony_ci bank->eff2_gain = 57762306a36Sopenharmony_ci bank->eff2_gain_end = vol_right; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int snd_ymfpci_ac3_init(struct snd_ymfpci *chip) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, &chip->pci->dev, 58762306a36Sopenharmony_ci 4096, &chip->ac3_tmp_base) < 0) 58862306a36Sopenharmony_ci return -ENOMEM; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci chip->bank_effect[3][0]->base = 59162306a36Sopenharmony_ci chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr); 59262306a36Sopenharmony_ci chip->bank_effect[3][0]->loop_end = 59362306a36Sopenharmony_ci chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024); 59462306a36Sopenharmony_ci chip->bank_effect[4][0]->base = 59562306a36Sopenharmony_ci chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr + 2048); 59662306a36Sopenharmony_ci chip->bank_effect[4][0]->loop_end = 59762306a36Sopenharmony_ci chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 60062306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, 60162306a36Sopenharmony_ci snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) | 3 << 3); 60262306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int snd_ymfpci_ac3_done(struct snd_ymfpci *chip) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 60962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, 61062306a36Sopenharmony_ci snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3)); 61162306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 61262306a36Sopenharmony_ci // snd_ymfpci_irq_wait(chip); 61362306a36Sopenharmony_ci if (chip->ac3_tmp_base.area) { 61462306a36Sopenharmony_ci snd_dma_free_pages(&chip->ac3_tmp_base); 61562306a36Sopenharmony_ci chip->ac3_tmp_base.area = NULL; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci return 0; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic int snd_ymfpci_playback_hw_params(struct snd_pcm_substream *substream, 62162306a36Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 62462306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 62562306a36Sopenharmony_ci int err; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci err = snd_ymfpci_pcm_voice_alloc(ypcm, params_channels(hw_params)); 62862306a36Sopenharmony_ci if (err < 0) 62962306a36Sopenharmony_ci return err; 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic int snd_ymfpci_playback_hw_free(struct snd_pcm_substream *substream) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 63662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 63762306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (runtime->private_data == NULL) 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci ypcm = runtime->private_data; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* wait, until the PCI operations are not finished */ 64462306a36Sopenharmony_ci snd_ymfpci_irq_wait(chip); 64562306a36Sopenharmony_ci if (ypcm->voices[1]) { 64662306a36Sopenharmony_ci snd_ymfpci_voice_free(chip, ypcm->voices[1]); 64762306a36Sopenharmony_ci ypcm->voices[1] = NULL; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci if (ypcm->voices[0]) { 65062306a36Sopenharmony_ci snd_ymfpci_voice_free(chip, ypcm->voices[0]); 65162306a36Sopenharmony_ci ypcm->voices[0] = NULL; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int snd_ymfpci_playback_prepare(struct snd_pcm_substream *substream) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 65962306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 66062306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 66162306a36Sopenharmony_ci struct snd_kcontrol *kctl; 66262306a36Sopenharmony_ci unsigned int nvoice; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci ypcm->period_size = runtime->period_size; 66562306a36Sopenharmony_ci ypcm->buffer_size = runtime->buffer_size; 66662306a36Sopenharmony_ci ypcm->period_pos = 0; 66762306a36Sopenharmony_ci ypcm->last_pos = 0; 66862306a36Sopenharmony_ci for (nvoice = 0; nvoice < runtime->channels; nvoice++) 66962306a36Sopenharmony_ci snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime, 67062306a36Sopenharmony_ci substream->pcm == chip->pcm); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (substream->pcm == chip->pcm && !ypcm->use_441_slot) { 67362306a36Sopenharmony_ci kctl = chip->pcm_mixer[substream->number].ctl; 67462306a36Sopenharmony_ci kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 67562306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic int snd_ymfpci_capture_hw_free(struct snd_pcm_substream *substream) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* wait, until the PCI operations are not finished */ 68562306a36Sopenharmony_ci snd_ymfpci_irq_wait(chip); 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic int snd_ymfpci_capture_prepare(struct snd_pcm_substream *substream) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 69262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 69362306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 69462306a36Sopenharmony_ci struct snd_ymfpci_capture_bank * bank; 69562306a36Sopenharmony_ci int nbank; 69662306a36Sopenharmony_ci u32 rate, format; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci ypcm->period_size = runtime->period_size; 69962306a36Sopenharmony_ci ypcm->buffer_size = runtime->buffer_size; 70062306a36Sopenharmony_ci ypcm->period_pos = 0; 70162306a36Sopenharmony_ci ypcm->last_pos = 0; 70262306a36Sopenharmony_ci ypcm->shift = 0; 70362306a36Sopenharmony_ci rate = ((48000 * 4096) / runtime->rate) - 1; 70462306a36Sopenharmony_ci format = 0; 70562306a36Sopenharmony_ci if (runtime->channels == 2) { 70662306a36Sopenharmony_ci format |= 2; 70762306a36Sopenharmony_ci ypcm->shift++; 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci if (snd_pcm_format_width(runtime->format) == 8) 71062306a36Sopenharmony_ci format |= 1; 71162306a36Sopenharmony_ci else 71262306a36Sopenharmony_ci ypcm->shift++; 71362306a36Sopenharmony_ci switch (ypcm->capture_bank_number) { 71462306a36Sopenharmony_ci case 0: 71562306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_RECFORMAT, format); 71662306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_RECSLOTSR, rate); 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci case 1: 71962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_ADCFORMAT, format); 72062306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_ADCSLOTSR, rate); 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci for (nbank = 0; nbank < 2; nbank++) { 72462306a36Sopenharmony_ci bank = chip->bank_capture[ypcm->capture_bank_number][nbank]; 72562306a36Sopenharmony_ci bank->base = cpu_to_le32(runtime->dma_addr); 72662306a36Sopenharmony_ci bank->loop_end = cpu_to_le32(ypcm->buffer_size << ypcm->shift); 72762306a36Sopenharmony_ci bank->start = 0; 72862306a36Sopenharmony_ci bank->num_of_loops = 0; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci return 0; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ymfpci_playback_pointer(struct snd_pcm_substream *substream) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 73662306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 73762306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 73862306a36Sopenharmony_ci struct snd_ymfpci_voice *voice = ypcm->voices[0]; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!(ypcm->running && voice)) 74162306a36Sopenharmony_ci return 0; 74262306a36Sopenharmony_ci return le32_to_cpu(voice->bank[chip->active_bank].start); 74362306a36Sopenharmony_ci} 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_cistatic snd_pcm_uframes_t snd_ymfpci_capture_pointer(struct snd_pcm_substream *substream) 74662306a36Sopenharmony_ci{ 74762306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 74862306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 74962306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (!ypcm->running) 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci return le32_to_cpu(chip->bank_capture[ypcm->capture_bank_number][chip->active_bank]->start) >> ypcm->shift; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic void snd_ymfpci_irq_wait(struct snd_ymfpci *chip) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci wait_queue_entry_t wait; 75962306a36Sopenharmony_ci int loops = 4; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci while (loops-- > 0) { 76262306a36Sopenharmony_ci if ((snd_ymfpci_readl(chip, YDSXGR_MODE) & 3) == 0) 76362306a36Sopenharmony_ci continue; 76462306a36Sopenharmony_ci init_waitqueue_entry(&wait, current); 76562306a36Sopenharmony_ci add_wait_queue(&chip->interrupt_sleep, &wait); 76662306a36Sopenharmony_ci atomic_inc(&chip->interrupt_sleep_count); 76762306a36Sopenharmony_ci schedule_timeout_uninterruptible(msecs_to_jiffies(50)); 76862306a36Sopenharmony_ci remove_wait_queue(&chip->interrupt_sleep, &wait); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci} 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct snd_ymfpci *chip = dev_id; 77562306a36Sopenharmony_ci u32 status, nvoice, mode; 77662306a36Sopenharmony_ci struct snd_ymfpci_voice *voice; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci status = snd_ymfpci_readl(chip, YDSXGR_STATUS); 77962306a36Sopenharmony_ci if (status & 0x80000000) { 78062306a36Sopenharmony_ci chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT) & 1; 78162306a36Sopenharmony_ci spin_lock(&chip->voice_lock); 78262306a36Sopenharmony_ci for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) { 78362306a36Sopenharmony_ci voice = &chip->voices[nvoice]; 78462306a36Sopenharmony_ci if (voice->interrupt) 78562306a36Sopenharmony_ci voice->interrupt(chip, voice); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) { 78862306a36Sopenharmony_ci if (chip->capture_substream[nvoice]) 78962306a36Sopenharmony_ci snd_ymfpci_pcm_capture_interrupt(chip->capture_substream[nvoice]); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci#if 0 79262306a36Sopenharmony_ci for (nvoice = 0; nvoice < YDSXG_EFFECT_VOICES; nvoice++) { 79362306a36Sopenharmony_ci if (chip->effect_substream[nvoice]) 79462306a36Sopenharmony_ci snd_ymfpci_pcm_effect_interrupt(chip->effect_substream[nvoice]); 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci#endif 79762306a36Sopenharmony_ci spin_unlock(&chip->voice_lock); 79862306a36Sopenharmony_ci spin_lock(&chip->reg_lock); 79962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_STATUS, 0x80000000); 80062306a36Sopenharmony_ci mode = snd_ymfpci_readl(chip, YDSXGR_MODE) | 2; 80162306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, mode); 80262306a36Sopenharmony_ci spin_unlock(&chip->reg_lock); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci if (atomic_read(&chip->interrupt_sleep_count)) { 80562306a36Sopenharmony_ci atomic_set(&chip->interrupt_sleep_count, 0); 80662306a36Sopenharmony_ci wake_up(&chip->interrupt_sleep); 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG); 81162306a36Sopenharmony_ci if (status & 1) { 81262306a36Sopenharmony_ci if (chip->timer) 81362306a36Sopenharmony_ci snd_timer_interrupt(chip->timer, chip->timer_ticks); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (chip->rawmidi) 81862306a36Sopenharmony_ci snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data); 81962306a36Sopenharmony_ci return IRQ_HANDLED; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ymfpci_playback = 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 82562306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 82662306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 82762306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 82862306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 82962306a36Sopenharmony_ci SNDRV_PCM_INFO_RESUME), 83062306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 83162306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 83262306a36Sopenharmony_ci .rate_min = 8000, 83362306a36Sopenharmony_ci .rate_max = 48000, 83462306a36Sopenharmony_ci .channels_min = 1, 83562306a36Sopenharmony_ci .channels_max = 2, 83662306a36Sopenharmony_ci .buffer_bytes_max = 256 * 1024, /* FIXME: enough? */ 83762306a36Sopenharmony_ci .period_bytes_min = 64, 83862306a36Sopenharmony_ci .period_bytes_max = 256 * 1024, /* FIXME: enough? */ 83962306a36Sopenharmony_ci .periods_min = 3, 84062306a36Sopenharmony_ci .periods_max = 1024, 84162306a36Sopenharmony_ci .fifo_size = 0, 84262306a36Sopenharmony_ci}; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_ymfpci_capture = 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci .info = (SNDRV_PCM_INFO_MMAP | 84762306a36Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 84862306a36Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 84962306a36Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 85062306a36Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 85162306a36Sopenharmony_ci SNDRV_PCM_INFO_RESUME), 85262306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE, 85362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, 85462306a36Sopenharmony_ci .rate_min = 8000, 85562306a36Sopenharmony_ci .rate_max = 48000, 85662306a36Sopenharmony_ci .channels_min = 1, 85762306a36Sopenharmony_ci .channels_max = 2, 85862306a36Sopenharmony_ci .buffer_bytes_max = 256 * 1024, /* FIXME: enough? */ 85962306a36Sopenharmony_ci .period_bytes_min = 64, 86062306a36Sopenharmony_ci .period_bytes_max = 256 * 1024, /* FIXME: enough? */ 86162306a36Sopenharmony_ci .periods_min = 3, 86262306a36Sopenharmony_ci .periods_max = 1024, 86362306a36Sopenharmony_ci .fifo_size = 0, 86462306a36Sopenharmony_ci}; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic void snd_ymfpci_pcm_free_substream(struct snd_pcm_runtime *runtime) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci kfree(runtime->private_data); 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic int snd_ymfpci_playback_open_1(struct snd_pcm_substream *substream) 87262306a36Sopenharmony_ci{ 87362306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 87462306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 87562306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 87662306a36Sopenharmony_ci int err; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci runtime->hw = snd_ymfpci_playback; 87962306a36Sopenharmony_ci /* FIXME? True value is 256/48 = 5.33333 ms */ 88062306a36Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(runtime, 88162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_TIME, 88262306a36Sopenharmony_ci 5334, UINT_MAX); 88362306a36Sopenharmony_ci if (err < 0) 88462306a36Sopenharmony_ci return err; 88562306a36Sopenharmony_ci err = snd_pcm_hw_rule_noresample(runtime, 48000); 88662306a36Sopenharmony_ci if (err < 0) 88762306a36Sopenharmony_ci return err; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); 89062306a36Sopenharmony_ci if (ypcm == NULL) 89162306a36Sopenharmony_ci return -ENOMEM; 89262306a36Sopenharmony_ci ypcm->chip = chip; 89362306a36Sopenharmony_ci ypcm->type = PLAYBACK_VOICE; 89462306a36Sopenharmony_ci ypcm->substream = substream; 89562306a36Sopenharmony_ci runtime->private_data = ypcm; 89662306a36Sopenharmony_ci runtime->private_free = snd_ymfpci_pcm_free_substream; 89762306a36Sopenharmony_ci return 0; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/* call with spinlock held */ 90162306a36Sopenharmony_cistatic void ymfpci_open_extension(struct snd_ymfpci *chip) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci if (! chip->rear_opened) { 90462306a36Sopenharmony_ci if (! chip->spdif_opened) /* set AC3 */ 90562306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, 90662306a36Sopenharmony_ci snd_ymfpci_readl(chip, YDSXGR_MODE) | (1 << 30)); 90762306a36Sopenharmony_ci /* enable second codec (4CHEN) */ 90862306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SECCONFIG, 90962306a36Sopenharmony_ci (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) | 0x0010); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci/* call with spinlock held */ 91462306a36Sopenharmony_cistatic void ymfpci_close_extension(struct snd_ymfpci *chip) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci if (! chip->rear_opened) { 91762306a36Sopenharmony_ci if (! chip->spdif_opened) 91862306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, 91962306a36Sopenharmony_ci snd_ymfpci_readl(chip, YDSXGR_MODE) & ~(1 << 30)); 92062306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SECCONFIG, 92162306a36Sopenharmony_ci (snd_ymfpci_readw(chip, YDSXGR_SECCONFIG) & ~0x0330) & ~0x0010); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int snd_ymfpci_playback_open(struct snd_pcm_substream *substream) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 92862306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 92962306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 93062306a36Sopenharmony_ci int err; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci err = snd_ymfpci_playback_open_1(substream); 93362306a36Sopenharmony_ci if (err < 0) 93462306a36Sopenharmony_ci return err; 93562306a36Sopenharmony_ci ypcm = runtime->private_data; 93662306a36Sopenharmony_ci ypcm->output_front = 1; 93762306a36Sopenharmony_ci ypcm->output_rear = chip->mode_dup4ch ? 1 : 0; 93862306a36Sopenharmony_ci ypcm->swap_rear = 0; 93962306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 94062306a36Sopenharmony_ci if (ypcm->output_rear) { 94162306a36Sopenharmony_ci ymfpci_open_extension(chip); 94262306a36Sopenharmony_ci chip->rear_opened++; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int snd_ymfpci_playback_spdif_open(struct snd_pcm_substream *substream) 94962306a36Sopenharmony_ci{ 95062306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 95162306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 95262306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 95362306a36Sopenharmony_ci int err; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci err = snd_ymfpci_playback_open_1(substream); 95662306a36Sopenharmony_ci if (err < 0) 95762306a36Sopenharmony_ci return err; 95862306a36Sopenharmony_ci ypcm = runtime->private_data; 95962306a36Sopenharmony_ci ypcm->output_front = 0; 96062306a36Sopenharmony_ci ypcm->output_rear = 1; 96162306a36Sopenharmony_ci ypcm->swap_rear = 1; 96262306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 96362306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, 96462306a36Sopenharmony_ci snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) | 2); 96562306a36Sopenharmony_ci ymfpci_open_extension(chip); 96662306a36Sopenharmony_ci chip->spdif_pcm_bits = chip->spdif_bits; 96762306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits); 96862306a36Sopenharmony_ci chip->spdif_opened++; 96962306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci chip->spdif_pcm_ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; 97262306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | 97362306a36Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id); 97462306a36Sopenharmony_ci return 0; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic int snd_ymfpci_playback_4ch_open(struct snd_pcm_substream *substream) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 98062306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 98162306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 98262306a36Sopenharmony_ci int err; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci err = snd_ymfpci_playback_open_1(substream); 98562306a36Sopenharmony_ci if (err < 0) 98662306a36Sopenharmony_ci return err; 98762306a36Sopenharmony_ci ypcm = runtime->private_data; 98862306a36Sopenharmony_ci ypcm->output_front = 0; 98962306a36Sopenharmony_ci ypcm->output_rear = 1; 99062306a36Sopenharmony_ci ypcm->swap_rear = 0; 99162306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 99262306a36Sopenharmony_ci ymfpci_open_extension(chip); 99362306a36Sopenharmony_ci chip->rear_opened++; 99462306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 99562306a36Sopenharmony_ci return 0; 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic int snd_ymfpci_capture_open(struct snd_pcm_substream *substream, 99962306a36Sopenharmony_ci u32 capture_bank_number) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 100262306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 100362306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm; 100462306a36Sopenharmony_ci int err; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci runtime->hw = snd_ymfpci_capture; 100762306a36Sopenharmony_ci /* FIXME? True value is 256/48 = 5.33333 ms */ 100862306a36Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(runtime, 100962306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_TIME, 101062306a36Sopenharmony_ci 5334, UINT_MAX); 101162306a36Sopenharmony_ci if (err < 0) 101262306a36Sopenharmony_ci return err; 101362306a36Sopenharmony_ci err = snd_pcm_hw_rule_noresample(runtime, 48000); 101462306a36Sopenharmony_ci if (err < 0) 101562306a36Sopenharmony_ci return err; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); 101862306a36Sopenharmony_ci if (ypcm == NULL) 101962306a36Sopenharmony_ci return -ENOMEM; 102062306a36Sopenharmony_ci ypcm->chip = chip; 102162306a36Sopenharmony_ci ypcm->type = capture_bank_number + CAPTURE_REC; 102262306a36Sopenharmony_ci ypcm->substream = substream; 102362306a36Sopenharmony_ci ypcm->capture_bank_number = capture_bank_number; 102462306a36Sopenharmony_ci chip->capture_substream[capture_bank_number] = substream; 102562306a36Sopenharmony_ci runtime->private_data = ypcm; 102662306a36Sopenharmony_ci runtime->private_free = snd_ymfpci_pcm_free_substream; 102762306a36Sopenharmony_ci snd_ymfpci_hw_start(chip); 102862306a36Sopenharmony_ci return 0; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int snd_ymfpci_capture_rec_open(struct snd_pcm_substream *substream) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci return snd_ymfpci_capture_open(substream, 0); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic int snd_ymfpci_capture_ac97_open(struct snd_pcm_substream *substream) 103762306a36Sopenharmony_ci{ 103862306a36Sopenharmony_ci return snd_ymfpci_capture_open(substream, 1); 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic int snd_ymfpci_playback_close_1(struct snd_pcm_substream *substream) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int snd_ymfpci_playback_close(struct snd_pcm_substream *substream) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 104962306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 105262306a36Sopenharmony_ci if (ypcm->output_rear && chip->rear_opened > 0) { 105362306a36Sopenharmony_ci chip->rear_opened--; 105462306a36Sopenharmony_ci ymfpci_close_extension(chip); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 105762306a36Sopenharmony_ci return snd_ymfpci_playback_close_1(substream); 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_cistatic int snd_ymfpci_playback_spdif_close(struct snd_pcm_substream *substream) 106162306a36Sopenharmony_ci{ 106262306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 106562306a36Sopenharmony_ci chip->spdif_opened = 0; 106662306a36Sopenharmony_ci ymfpci_close_extension(chip); 106762306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, 106862306a36Sopenharmony_ci snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & ~2); 106962306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); 107062306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 107162306a36Sopenharmony_ci chip->spdif_pcm_ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; 107262306a36Sopenharmony_ci snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE | 107362306a36Sopenharmony_ci SNDRV_CTL_EVENT_MASK_INFO, &chip->spdif_pcm_ctl->id); 107462306a36Sopenharmony_ci return snd_ymfpci_playback_close_1(substream); 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int snd_ymfpci_playback_4ch_close(struct snd_pcm_substream *substream) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 108262306a36Sopenharmony_ci if (chip->rear_opened > 0) { 108362306a36Sopenharmony_ci chip->rear_opened--; 108462306a36Sopenharmony_ci ymfpci_close_extension(chip); 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 108762306a36Sopenharmony_ci return snd_ymfpci_playback_close_1(substream); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_cistatic int snd_ymfpci_capture_close(struct snd_pcm_substream *substream) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_pcm_substream_chip(substream); 109362306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 109462306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = runtime->private_data; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci if (ypcm != NULL) { 109762306a36Sopenharmony_ci chip->capture_substream[ypcm->capture_bank_number] = NULL; 109862306a36Sopenharmony_ci snd_ymfpci_hw_stop(chip); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci return 0; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_ops = { 110462306a36Sopenharmony_ci .open = snd_ymfpci_playback_open, 110562306a36Sopenharmony_ci .close = snd_ymfpci_playback_close, 110662306a36Sopenharmony_ci .hw_params = snd_ymfpci_playback_hw_params, 110762306a36Sopenharmony_ci .hw_free = snd_ymfpci_playback_hw_free, 110862306a36Sopenharmony_ci .prepare = snd_ymfpci_playback_prepare, 110962306a36Sopenharmony_ci .trigger = snd_ymfpci_playback_trigger, 111062306a36Sopenharmony_ci .pointer = snd_ymfpci_playback_pointer, 111162306a36Sopenharmony_ci}; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_capture_rec_ops = { 111462306a36Sopenharmony_ci .open = snd_ymfpci_capture_rec_open, 111562306a36Sopenharmony_ci .close = snd_ymfpci_capture_close, 111662306a36Sopenharmony_ci .hw_free = snd_ymfpci_capture_hw_free, 111762306a36Sopenharmony_ci .prepare = snd_ymfpci_capture_prepare, 111862306a36Sopenharmony_ci .trigger = snd_ymfpci_capture_trigger, 111962306a36Sopenharmony_ci .pointer = snd_ymfpci_capture_pointer, 112062306a36Sopenharmony_ci}; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ciint snd_ymfpci_pcm(struct snd_ymfpci *chip, int device) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct snd_pcm *pcm; 112562306a36Sopenharmony_ci int err; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "YMFPCI", device, 32, 1, &pcm); 112862306a36Sopenharmony_ci if (err < 0) 112962306a36Sopenharmony_ci return err; 113062306a36Sopenharmony_ci pcm->private_data = chip; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_ops); 113362306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_rec_ops); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci /* global setup */ 113662306a36Sopenharmony_ci pcm->info_flags = 0; 113762306a36Sopenharmony_ci strcpy(pcm->name, "YMFPCI"); 113862306a36Sopenharmony_ci chip->pcm = pcm; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 114162306a36Sopenharmony_ci &chip->pci->dev, 64*1024, 256*1024); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, 114462306a36Sopenharmony_ci snd_pcm_std_chmaps, 2, 0, NULL); 114562306a36Sopenharmony_ci} 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { 114862306a36Sopenharmony_ci .open = snd_ymfpci_capture_ac97_open, 114962306a36Sopenharmony_ci .close = snd_ymfpci_capture_close, 115062306a36Sopenharmony_ci .hw_free = snd_ymfpci_capture_hw_free, 115162306a36Sopenharmony_ci .prepare = snd_ymfpci_capture_prepare, 115262306a36Sopenharmony_ci .trigger = snd_ymfpci_capture_trigger, 115362306a36Sopenharmony_ci .pointer = snd_ymfpci_capture_pointer, 115462306a36Sopenharmony_ci}; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ciint snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct snd_pcm *pcm; 115962306a36Sopenharmony_ci int err; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "YMFPCI - PCM2", device, 0, 1, &pcm); 116262306a36Sopenharmony_ci if (err < 0) 116362306a36Sopenharmony_ci return err; 116462306a36Sopenharmony_ci pcm->private_data = chip; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ymfpci_capture_ac97_ops); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci /* global setup */ 116962306a36Sopenharmony_ci pcm->info_flags = 0; 117062306a36Sopenharmony_ci sprintf(pcm->name, "YMFPCI - %s", 117162306a36Sopenharmony_ci chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97"); 117262306a36Sopenharmony_ci chip->pcm2 = pcm; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 117562306a36Sopenharmony_ci &chip->pci->dev, 64*1024, 256*1024); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci return 0; 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = { 118162306a36Sopenharmony_ci .open = snd_ymfpci_playback_spdif_open, 118262306a36Sopenharmony_ci .close = snd_ymfpci_playback_spdif_close, 118362306a36Sopenharmony_ci .hw_params = snd_ymfpci_playback_hw_params, 118462306a36Sopenharmony_ci .hw_free = snd_ymfpci_playback_hw_free, 118562306a36Sopenharmony_ci .prepare = snd_ymfpci_playback_prepare, 118662306a36Sopenharmony_ci .trigger = snd_ymfpci_playback_trigger, 118762306a36Sopenharmony_ci .pointer = snd_ymfpci_playback_pointer, 118862306a36Sopenharmony_ci}; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ciint snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct snd_pcm *pcm; 119362306a36Sopenharmony_ci int err; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "YMFPCI - IEC958", device, 1, 0, &pcm); 119662306a36Sopenharmony_ci if (err < 0) 119762306a36Sopenharmony_ci return err; 119862306a36Sopenharmony_ci pcm->private_data = chip; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_spdif_ops); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* global setup */ 120362306a36Sopenharmony_ci pcm->info_flags = 0; 120462306a36Sopenharmony_ci strcpy(pcm->name, "YMFPCI - IEC958"); 120562306a36Sopenharmony_ci chip->pcm_spdif = pcm; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 120862306a36Sopenharmony_ci &chip->pci->dev, 64*1024, 256*1024); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci return 0; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_ymfpci_playback_4ch_ops = { 121462306a36Sopenharmony_ci .open = snd_ymfpci_playback_4ch_open, 121562306a36Sopenharmony_ci .close = snd_ymfpci_playback_4ch_close, 121662306a36Sopenharmony_ci .hw_params = snd_ymfpci_playback_hw_params, 121762306a36Sopenharmony_ci .hw_free = snd_ymfpci_playback_hw_free, 121862306a36Sopenharmony_ci .prepare = snd_ymfpci_playback_prepare, 121962306a36Sopenharmony_ci .trigger = snd_ymfpci_playback_trigger, 122062306a36Sopenharmony_ci .pointer = snd_ymfpci_playback_pointer, 122162306a36Sopenharmony_ci}; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic const struct snd_pcm_chmap_elem surround_map[] = { 122462306a36Sopenharmony_ci { .channels = 1, 122562306a36Sopenharmony_ci .map = { SNDRV_CHMAP_MONO } }, 122662306a36Sopenharmony_ci { .channels = 2, 122762306a36Sopenharmony_ci .map = { SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, 122862306a36Sopenharmony_ci { } 122962306a36Sopenharmony_ci}; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ciint snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct snd_pcm *pcm; 123462306a36Sopenharmony_ci int err; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci err = snd_pcm_new(chip->card, "YMFPCI - Rear", device, 1, 0, &pcm); 123762306a36Sopenharmony_ci if (err < 0) 123862306a36Sopenharmony_ci return err; 123962306a36Sopenharmony_ci pcm->private_data = chip; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ymfpci_playback_4ch_ops); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* global setup */ 124462306a36Sopenharmony_ci pcm->info_flags = 0; 124562306a36Sopenharmony_ci strcpy(pcm->name, "YMFPCI - Rear PCM"); 124662306a36Sopenharmony_ci chip->pcm_4ch = pcm; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 124962306a36Sopenharmony_ci &chip->pci->dev, 64*1024, 256*1024); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, 125262306a36Sopenharmony_ci surround_map, 2, 0, NULL); 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int snd_ymfpci_spdif_default_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 125862306a36Sopenharmony_ci uinfo->count = 1; 125962306a36Sopenharmony_ci return 0; 126062306a36Sopenharmony_ci} 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_cistatic int snd_ymfpci_spdif_default_get(struct snd_kcontrol *kcontrol, 126362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 126462306a36Sopenharmony_ci{ 126562306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 126862306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = (chip->spdif_bits >> 0) & 0xff; 126962306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = (chip->spdif_bits >> 8) & 0xff; 127062306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; 127162306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 127262306a36Sopenharmony_ci return 0; 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol, 127662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 127962306a36Sopenharmony_ci unsigned int val; 128062306a36Sopenharmony_ci int change; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) | 128362306a36Sopenharmony_ci (ucontrol->value.iec958.status[1] << 8); 128462306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 128562306a36Sopenharmony_ci change = chip->spdif_bits != val; 128662306a36Sopenharmony_ci chip->spdif_bits = val; 128762306a36Sopenharmony_ci if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 1) && chip->pcm_spdif == NULL) 128862306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); 128962306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 129062306a36Sopenharmony_ci return change; 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_default = 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 129662306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 129762306a36Sopenharmony_ci .info = snd_ymfpci_spdif_default_info, 129862306a36Sopenharmony_ci .get = snd_ymfpci_spdif_default_get, 129962306a36Sopenharmony_ci .put = snd_ymfpci_spdif_default_put 130062306a36Sopenharmony_ci}; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_cistatic int snd_ymfpci_spdif_mask_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 130362306a36Sopenharmony_ci{ 130462306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 130562306a36Sopenharmony_ci uinfo->count = 1; 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol, 131062306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 131562306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = 0x3e; 131662306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = 0xff; 131762306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 131862306a36Sopenharmony_ci return 0; 131962306a36Sopenharmony_ci} 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_mask = 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 132462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 132562306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), 132662306a36Sopenharmony_ci .info = snd_ymfpci_spdif_mask_info, 132762306a36Sopenharmony_ci .get = snd_ymfpci_spdif_mask_get, 132862306a36Sopenharmony_ci}; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic int snd_ymfpci_spdif_stream_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 133162306a36Sopenharmony_ci{ 133262306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 133362306a36Sopenharmony_ci uinfo->count = 1; 133462306a36Sopenharmony_ci return 0; 133562306a36Sopenharmony_ci} 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic int snd_ymfpci_spdif_stream_get(struct snd_kcontrol *kcontrol, 133862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 134362306a36Sopenharmony_ci ucontrol->value.iec958.status[0] = (chip->spdif_pcm_bits >> 0) & 0xff; 134462306a36Sopenharmony_ci ucontrol->value.iec958.status[1] = (chip->spdif_pcm_bits >> 8) & 0xff; 134562306a36Sopenharmony_ci ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; 134662306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 134762306a36Sopenharmony_ci return 0; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol, 135162306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 135462306a36Sopenharmony_ci unsigned int val; 135562306a36Sopenharmony_ci int change; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci val = ((ucontrol->value.iec958.status[0] & 0x3e) << 0) | 135862306a36Sopenharmony_ci (ucontrol->value.iec958.status[1] << 8); 135962306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 136062306a36Sopenharmony_ci change = chip->spdif_pcm_bits != val; 136162306a36Sopenharmony_ci chip->spdif_pcm_bits = val; 136262306a36Sopenharmony_ci if ((snd_ymfpci_readw(chip, YDSXGR_SPDIFOUTCTRL) & 2)) 136362306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_pcm_bits); 136462306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 136562306a36Sopenharmony_ci return change; 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_spdif_stream = 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, 137162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 137262306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM), 137362306a36Sopenharmony_ci .info = snd_ymfpci_spdif_stream_info, 137462306a36Sopenharmony_ci .get = snd_ymfpci_spdif_stream_get, 137562306a36Sopenharmony_ci .put = snd_ymfpci_spdif_stream_put 137662306a36Sopenharmony_ci}; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic int snd_ymfpci_drec_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci static const char *const texts[3] = {"AC'97", "IEC958", "ZV Port"}; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci return snd_ctl_enum_info(info, 1, 3, texts); 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic int snd_ymfpci_drec_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 138862306a36Sopenharmony_ci u16 reg; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 139162306a36Sopenharmony_ci reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); 139262306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 139362306a36Sopenharmony_ci if (!(reg & 0x100)) 139462306a36Sopenharmony_ci value->value.enumerated.item[0] = 0; 139562306a36Sopenharmony_ci else 139662306a36Sopenharmony_ci value->value.enumerated.item[0] = 1 + ((reg & 0x200) != 0); 139762306a36Sopenharmony_ci return 0; 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 140362306a36Sopenharmony_ci u16 reg, old_reg; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 140662306a36Sopenharmony_ci old_reg = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); 140762306a36Sopenharmony_ci if (value->value.enumerated.item[0] == 0) 140862306a36Sopenharmony_ci reg = old_reg & ~0x100; 140962306a36Sopenharmony_ci else 141062306a36Sopenharmony_ci reg = (old_reg & ~0x300) | 0x100 | ((value->value.enumerated.item[0] == 2) << 9); 141162306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, reg); 141262306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 141362306a36Sopenharmony_ci return reg != old_reg; 141462306a36Sopenharmony_ci} 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_drec_source = { 141762306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 141862306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 141962306a36Sopenharmony_ci .name = "Direct Recording Source", 142062306a36Sopenharmony_ci .info = snd_ymfpci_drec_source_info, 142162306a36Sopenharmony_ci .get = snd_ymfpci_drec_source_get, 142262306a36Sopenharmony_ci .put = snd_ymfpci_drec_source_put 142362306a36Sopenharmony_ci}; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci/* 142662306a36Sopenharmony_ci * Mixer controls 142762306a36Sopenharmony_ci */ 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci#define YMFPCI_SINGLE(xname, xindex, reg, shift) \ 143062306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 143162306a36Sopenharmony_ci .info = snd_ymfpci_info_single, \ 143262306a36Sopenharmony_ci .get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \ 143362306a36Sopenharmony_ci .private_value = ((reg) | ((shift) << 16)) } 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci#define snd_ymfpci_info_single snd_ctl_boolean_mono_info 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic int snd_ymfpci_get_single(struct snd_kcontrol *kcontrol, 143862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 144162306a36Sopenharmony_ci int reg = kcontrol->private_value & 0xffff; 144262306a36Sopenharmony_ci unsigned int shift = (kcontrol->private_value >> 16) & 0xff; 144362306a36Sopenharmony_ci unsigned int mask = 1; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci switch (reg) { 144662306a36Sopenharmony_ci case YDSXGR_SPDIFOUTCTRL: break; 144762306a36Sopenharmony_ci case YDSXGR_SPDIFINCTRL: break; 144862306a36Sopenharmony_ci default: return -EINVAL; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = 145162306a36Sopenharmony_ci (snd_ymfpci_readl(chip, reg) >> shift) & mask; 145262306a36Sopenharmony_ci return 0; 145362306a36Sopenharmony_ci} 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic int snd_ymfpci_put_single(struct snd_kcontrol *kcontrol, 145662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 145762306a36Sopenharmony_ci{ 145862306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 145962306a36Sopenharmony_ci int reg = kcontrol->private_value & 0xffff; 146062306a36Sopenharmony_ci unsigned int shift = (kcontrol->private_value >> 16) & 0xff; 146162306a36Sopenharmony_ci unsigned int mask = 1; 146262306a36Sopenharmony_ci int change; 146362306a36Sopenharmony_ci unsigned int val, oval; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci switch (reg) { 146662306a36Sopenharmony_ci case YDSXGR_SPDIFOUTCTRL: break; 146762306a36Sopenharmony_ci case YDSXGR_SPDIFINCTRL: break; 146862306a36Sopenharmony_ci default: return -EINVAL; 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci val = (ucontrol->value.integer.value[0] & mask); 147162306a36Sopenharmony_ci val <<= shift; 147262306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 147362306a36Sopenharmony_ci oval = snd_ymfpci_readl(chip, reg); 147462306a36Sopenharmony_ci val = (oval & ~(mask << shift)) | val; 147562306a36Sopenharmony_ci change = val != oval; 147662306a36Sopenharmony_ci snd_ymfpci_writel(chip, reg, val); 147762306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 147862306a36Sopenharmony_ci return change; 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic const DECLARE_TLV_DB_LINEAR(db_scale_native, TLV_DB_GAIN_MUTE, 0); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci#define YMFPCI_DOUBLE(xname, xindex, reg) \ 148462306a36Sopenharmony_ci{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 148562306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ 148662306a36Sopenharmony_ci .info = snd_ymfpci_info_double, \ 148762306a36Sopenharmony_ci .get = snd_ymfpci_get_double, .put = snd_ymfpci_put_double, \ 148862306a36Sopenharmony_ci .private_value = reg, \ 148962306a36Sopenharmony_ci .tlv = { .p = db_scale_native } } 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_cistatic int snd_ymfpci_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci unsigned int reg = kcontrol->private_value; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci if (reg < 0x80 || reg >= 0xc0) 149662306a36Sopenharmony_ci return -EINVAL; 149762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 149862306a36Sopenharmony_ci uinfo->count = 2; 149962306a36Sopenharmony_ci uinfo->value.integer.min = 0; 150062306a36Sopenharmony_ci uinfo->value.integer.max = 16383; 150162306a36Sopenharmony_ci return 0; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic int snd_ymfpci_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 150562306a36Sopenharmony_ci{ 150662306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 150762306a36Sopenharmony_ci unsigned int reg = kcontrol->private_value; 150862306a36Sopenharmony_ci unsigned int shift_left = 0, shift_right = 16, mask = 16383; 150962306a36Sopenharmony_ci unsigned int val; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (reg < 0x80 || reg >= 0xc0) 151262306a36Sopenharmony_ci return -EINVAL; 151362306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 151462306a36Sopenharmony_ci val = snd_ymfpci_readl(chip, reg); 151562306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 151662306a36Sopenharmony_ci ucontrol->value.integer.value[0] = (val >> shift_left) & mask; 151762306a36Sopenharmony_ci ucontrol->value.integer.value[1] = (val >> shift_right) & mask; 151862306a36Sopenharmony_ci return 0; 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cistatic int snd_ymfpci_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 152262306a36Sopenharmony_ci{ 152362306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 152462306a36Sopenharmony_ci unsigned int reg = kcontrol->private_value; 152562306a36Sopenharmony_ci unsigned int shift_left = 0, shift_right = 16, mask = 16383; 152662306a36Sopenharmony_ci int change; 152762306a36Sopenharmony_ci unsigned int val1, val2, oval; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (reg < 0x80 || reg >= 0xc0) 153062306a36Sopenharmony_ci return -EINVAL; 153162306a36Sopenharmony_ci val1 = ucontrol->value.integer.value[0] & mask; 153262306a36Sopenharmony_ci val2 = ucontrol->value.integer.value[1] & mask; 153362306a36Sopenharmony_ci val1 <<= shift_left; 153462306a36Sopenharmony_ci val2 <<= shift_right; 153562306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 153662306a36Sopenharmony_ci oval = snd_ymfpci_readl(chip, reg); 153762306a36Sopenharmony_ci val1 = (oval & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2; 153862306a36Sopenharmony_ci change = val1 != oval; 153962306a36Sopenharmony_ci snd_ymfpci_writel(chip, reg, val1); 154062306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 154162306a36Sopenharmony_ci return change; 154262306a36Sopenharmony_ci} 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_cistatic int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol, 154562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 154862306a36Sopenharmony_ci unsigned int reg = YDSXGR_NATIVEDACOUTVOL; 154962306a36Sopenharmony_ci unsigned int reg2 = YDSXGR_BUF441OUTVOL; 155062306a36Sopenharmony_ci int change; 155162306a36Sopenharmony_ci unsigned int value, oval; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci value = ucontrol->value.integer.value[0] & 0x3fff; 155462306a36Sopenharmony_ci value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16; 155562306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 155662306a36Sopenharmony_ci oval = snd_ymfpci_readl(chip, reg); 155762306a36Sopenharmony_ci change = value != oval; 155862306a36Sopenharmony_ci snd_ymfpci_writel(chip, reg, value); 155962306a36Sopenharmony_ci snd_ymfpci_writel(chip, reg2, value); 156062306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 156162306a36Sopenharmony_ci return change; 156262306a36Sopenharmony_ci} 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci/* 156562306a36Sopenharmony_ci * 4ch duplication 156662306a36Sopenharmony_ci */ 156762306a36Sopenharmony_ci#define snd_ymfpci_info_dup4ch snd_ctl_boolean_mono_info 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int snd_ymfpci_get_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 157262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->mode_dup4ch; 157362306a36Sopenharmony_ci return 0; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_cistatic int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 157762306a36Sopenharmony_ci{ 157862306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 157962306a36Sopenharmony_ci int change; 158062306a36Sopenharmony_ci change = (ucontrol->value.integer.value[0] != chip->mode_dup4ch); 158162306a36Sopenharmony_ci if (change) 158262306a36Sopenharmony_ci chip->mode_dup4ch = !!ucontrol->value.integer.value[0]; 158362306a36Sopenharmony_ci return change; 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_dup4ch = { 158762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 158862306a36Sopenharmony_ci .name = "4ch Duplication", 158962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 159062306a36Sopenharmony_ci .info = snd_ymfpci_info_dup4ch, 159162306a36Sopenharmony_ci .get = snd_ymfpci_get_dup4ch, 159262306a36Sopenharmony_ci .put = snd_ymfpci_put_dup4ch, 159362306a36Sopenharmony_ci}; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_controls[] = { 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 159862306a36Sopenharmony_ci .name = "Wave Playback Volume", 159962306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 160062306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_TLV_READ, 160162306a36Sopenharmony_ci .info = snd_ymfpci_info_double, 160262306a36Sopenharmony_ci .get = snd_ymfpci_get_double, 160362306a36Sopenharmony_ci .put = snd_ymfpci_put_nativedacvol, 160462306a36Sopenharmony_ci .private_value = YDSXGR_NATIVEDACOUTVOL, 160562306a36Sopenharmony_ci .tlv = { .p = db_scale_native }, 160662306a36Sopenharmony_ci}, 160762306a36Sopenharmony_ciYMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL), 160862306a36Sopenharmony_ciYMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL), 160962306a36Sopenharmony_ciYMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL), 161062306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Playback Volume", 0, YDSXGR_PRIADCOUTVOL), 161162306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Capture Volume", 0, YDSXGR_PRIADCLOOPVOL), 161262306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Playback Volume", 1, YDSXGR_SECADCOUTVOL), 161362306a36Sopenharmony_ciYMFPCI_DOUBLE("ADC Capture Volume", 1, YDSXGR_SECADCLOOPVOL), 161462306a36Sopenharmony_ciYMFPCI_DOUBLE("FM Legacy Playback Volume", 0, YDSXGR_LEGACYOUTVOL), 161562306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ", PLAYBACK,VOLUME), 0, YDSXGR_ZVOUTVOL), 161662306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("", CAPTURE,VOLUME), 0, YDSXGR_ZVLOOPVOL), 161762306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("AC97 ",PLAYBACK,VOLUME), 1, YDSXGR_SPDIFOUTVOL), 161862306a36Sopenharmony_ciYMFPCI_DOUBLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,VOLUME), 1, YDSXGR_SPDIFLOOPVOL), 161962306a36Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), 0, YDSXGR_SPDIFOUTCTRL, 0), 162062306a36Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, YDSXGR_SPDIFINCTRL, 0), 162162306a36Sopenharmony_ciYMFPCI_SINGLE(SNDRV_CTL_NAME_IEC958("Loop",NONE,NONE), 0, YDSXGR_SPDIFINCTRL, 4), 162262306a36Sopenharmony_ci}; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci/* 162662306a36Sopenharmony_ci * GPIO 162762306a36Sopenharmony_ci */ 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_cistatic int snd_ymfpci_get_gpio_out(struct snd_ymfpci *chip, int pin) 163062306a36Sopenharmony_ci{ 163162306a36Sopenharmony_ci u16 reg, mode; 163262306a36Sopenharmony_ci unsigned long flags; 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 163562306a36Sopenharmony_ci reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE); 163662306a36Sopenharmony_ci reg &= ~(1 << (pin + 8)); 163762306a36Sopenharmony_ci reg |= (1 << pin); 163862306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg); 163962306a36Sopenharmony_ci /* set the level mode for input line */ 164062306a36Sopenharmony_ci mode = snd_ymfpci_readw(chip, YDSXGR_GPIOTYPECONFIG); 164162306a36Sopenharmony_ci mode &= ~(3 << (pin * 2)); 164262306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GPIOTYPECONFIG, mode); 164362306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8))); 164462306a36Sopenharmony_ci mode = snd_ymfpci_readw(chip, YDSXGR_GPIOINSTATUS); 164562306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 164662306a36Sopenharmony_ci return (mode >> pin) & 1; 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic int snd_ymfpci_set_gpio_out(struct snd_ymfpci *chip, int pin, int enable) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci u16 reg; 165262306a36Sopenharmony_ci unsigned long flags; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 165562306a36Sopenharmony_ci reg = snd_ymfpci_readw(chip, YDSXGR_GPIOFUNCENABLE); 165662306a36Sopenharmony_ci reg &= ~(1 << pin); 165762306a36Sopenharmony_ci reg &= ~(1 << (pin + 8)); 165862306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg); 165962306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GPIOOUTCTRL, enable << pin); 166062306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GPIOFUNCENABLE, reg | (1 << (pin + 8))); 166162306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci return 0; 166462306a36Sopenharmony_ci} 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci#define snd_ymfpci_gpio_sw_info snd_ctl_boolean_mono_info 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_cistatic int snd_ymfpci_gpio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 166962306a36Sopenharmony_ci{ 167062306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 167162306a36Sopenharmony_ci int pin = (int)kcontrol->private_value; 167262306a36Sopenharmony_ci ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin); 167362306a36Sopenharmony_ci return 0; 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_cistatic int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 167962306a36Sopenharmony_ci int pin = (int)kcontrol->private_value; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci if (snd_ymfpci_get_gpio_out(chip, pin) != ucontrol->value.integer.value[0]) { 168262306a36Sopenharmony_ci snd_ymfpci_set_gpio_out(chip, pin, !!ucontrol->value.integer.value[0]); 168362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = snd_ymfpci_get_gpio_out(chip, pin); 168462306a36Sopenharmony_ci return 1; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci return 0; 168762306a36Sopenharmony_ci} 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_rear_shared = { 169062306a36Sopenharmony_ci .name = "Shared Rear/Line-In Switch", 169162306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 169262306a36Sopenharmony_ci .info = snd_ymfpci_gpio_sw_info, 169362306a36Sopenharmony_ci .get = snd_ymfpci_gpio_sw_get, 169462306a36Sopenharmony_ci .put = snd_ymfpci_gpio_sw_put, 169562306a36Sopenharmony_ci .private_value = 2, 169662306a36Sopenharmony_ci}; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci/* 169962306a36Sopenharmony_ci * PCM voice volume 170062306a36Sopenharmony_ci */ 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_cistatic int snd_ymfpci_pcm_vol_info(struct snd_kcontrol *kcontrol, 170362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 170462306a36Sopenharmony_ci{ 170562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 170662306a36Sopenharmony_ci uinfo->count = 2; 170762306a36Sopenharmony_ci uinfo->value.integer.min = 0; 170862306a36Sopenharmony_ci uinfo->value.integer.max = 0x8000; 170962306a36Sopenharmony_ci return 0; 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic int snd_ymfpci_pcm_vol_get(struct snd_kcontrol *kcontrol, 171362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 171662306a36Sopenharmony_ci unsigned int subs = kcontrol->id.subdevice; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci ucontrol->value.integer.value[0] = chip->pcm_mixer[subs].left; 171962306a36Sopenharmony_ci ucontrol->value.integer.value[1] = chip->pcm_mixer[subs].right; 172062306a36Sopenharmony_ci return 0; 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, 172462306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 172562306a36Sopenharmony_ci{ 172662306a36Sopenharmony_ci struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol); 172762306a36Sopenharmony_ci unsigned int subs = kcontrol->id.subdevice; 172862306a36Sopenharmony_ci struct snd_pcm_substream *substream; 172962306a36Sopenharmony_ci unsigned long flags; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (ucontrol->value.integer.value[0] != chip->pcm_mixer[subs].left || 173262306a36Sopenharmony_ci ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) { 173362306a36Sopenharmony_ci chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0]; 173462306a36Sopenharmony_ci chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1]; 173562306a36Sopenharmony_ci if (chip->pcm_mixer[subs].left > 0x8000) 173662306a36Sopenharmony_ci chip->pcm_mixer[subs].left = 0x8000; 173762306a36Sopenharmony_ci if (chip->pcm_mixer[subs].right > 0x8000) 173862306a36Sopenharmony_ci chip->pcm_mixer[subs].right = 0x8000; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci substream = (struct snd_pcm_substream *)kcontrol->private_value; 174162306a36Sopenharmony_ci spin_lock_irqsave(&chip->voice_lock, flags); 174262306a36Sopenharmony_ci if (substream->runtime && substream->runtime->private_data) { 174362306a36Sopenharmony_ci struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data; 174462306a36Sopenharmony_ci if (!ypcm->use_441_slot) 174562306a36Sopenharmony_ci ypcm->update_pcm_vol = 2; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->voice_lock, flags); 174862306a36Sopenharmony_ci return 1; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci return 0; 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cistatic const struct snd_kcontrol_new snd_ymfpci_pcm_volume = { 175462306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 175562306a36Sopenharmony_ci .name = "PCM Playback Volume", 175662306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 175762306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_INACTIVE, 175862306a36Sopenharmony_ci .info = snd_ymfpci_pcm_vol_info, 175962306a36Sopenharmony_ci .get = snd_ymfpci_pcm_vol_get, 176062306a36Sopenharmony_ci .put = snd_ymfpci_pcm_vol_put, 176162306a36Sopenharmony_ci}; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci/* 176562306a36Sopenharmony_ci * Mixer routines 176662306a36Sopenharmony_ci */ 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_cistatic void snd_ymfpci_mixer_free_ac97_bus(struct snd_ac97_bus *bus) 176962306a36Sopenharmony_ci{ 177062306a36Sopenharmony_ci struct snd_ymfpci *chip = bus->private_data; 177162306a36Sopenharmony_ci chip->ac97_bus = NULL; 177262306a36Sopenharmony_ci} 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_cistatic void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97) 177562306a36Sopenharmony_ci{ 177662306a36Sopenharmony_ci struct snd_ymfpci *chip = ac97->private_data; 177762306a36Sopenharmony_ci chip->ac97 = NULL; 177862306a36Sopenharmony_ci} 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ciint snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) 178162306a36Sopenharmony_ci{ 178262306a36Sopenharmony_ci struct snd_ac97_template ac97; 178362306a36Sopenharmony_ci struct snd_kcontrol *kctl; 178462306a36Sopenharmony_ci struct snd_pcm_substream *substream; 178562306a36Sopenharmony_ci unsigned int idx; 178662306a36Sopenharmony_ci int err; 178762306a36Sopenharmony_ci static const struct snd_ac97_bus_ops ops = { 178862306a36Sopenharmony_ci .write = snd_ymfpci_codec_write, 178962306a36Sopenharmony_ci .read = snd_ymfpci_codec_read, 179062306a36Sopenharmony_ci }; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus); 179362306a36Sopenharmony_ci if (err < 0) 179462306a36Sopenharmony_ci return err; 179562306a36Sopenharmony_ci chip->ac97_bus->private_free = snd_ymfpci_mixer_free_ac97_bus; 179662306a36Sopenharmony_ci chip->ac97_bus->no_vra = 1; /* YMFPCI doesn't need VRA */ 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci memset(&ac97, 0, sizeof(ac97)); 179962306a36Sopenharmony_ci ac97.private_data = chip; 180062306a36Sopenharmony_ci ac97.private_free = snd_ymfpci_mixer_free_ac97; 180162306a36Sopenharmony_ci err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); 180262306a36Sopenharmony_ci if (err < 0) 180362306a36Sopenharmony_ci return err; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* to be sure */ 180662306a36Sopenharmony_ci snd_ac97_update_bits(chip->ac97, AC97_EXTENDED_STATUS, 180762306a36Sopenharmony_ci AC97_EA_VRA|AC97_EA_VRM, 0); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(snd_ymfpci_controls); idx++) { 181062306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_controls[idx], chip)); 181162306a36Sopenharmony_ci if (err < 0) 181262306a36Sopenharmony_ci return err; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci if (chip->ac97->ext_id & AC97_EI_SDAC) { 181562306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ymfpci_dup4ch, chip); 181662306a36Sopenharmony_ci err = snd_ctl_add(chip->card, kctl); 181762306a36Sopenharmony_ci if (err < 0) 181862306a36Sopenharmony_ci return err; 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci /* add S/PDIF control */ 182262306a36Sopenharmony_ci if (snd_BUG_ON(!chip->pcm_spdif)) 182362306a36Sopenharmony_ci return -ENXIO; 182462306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip); 182562306a36Sopenharmony_ci kctl->id.device = chip->pcm_spdif->device; 182662306a36Sopenharmony_ci err = snd_ctl_add(chip->card, kctl); 182762306a36Sopenharmony_ci if (err < 0) 182862306a36Sopenharmony_ci return err; 182962306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip); 183062306a36Sopenharmony_ci kctl->id.device = chip->pcm_spdif->device; 183162306a36Sopenharmony_ci err = snd_ctl_add(chip->card, kctl); 183262306a36Sopenharmony_ci if (err < 0) 183362306a36Sopenharmony_ci return err; 183462306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip); 183562306a36Sopenharmony_ci kctl->id.device = chip->pcm_spdif->device; 183662306a36Sopenharmony_ci err = snd_ctl_add(chip->card, kctl); 183762306a36Sopenharmony_ci if (err < 0) 183862306a36Sopenharmony_ci return err; 183962306a36Sopenharmony_ci chip->spdif_pcm_ctl = kctl; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci /* direct recording source */ 184262306a36Sopenharmony_ci if (chip->device_id == PCI_DEVICE_ID_YAMAHA_754) { 184362306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ymfpci_drec_source, chip); 184462306a36Sopenharmony_ci err = snd_ctl_add(chip->card, kctl); 184562306a36Sopenharmony_ci if (err < 0) 184662306a36Sopenharmony_ci return err; 184762306a36Sopenharmony_ci } 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci /* 185062306a36Sopenharmony_ci * shared rear/line-in 185162306a36Sopenharmony_ci */ 185262306a36Sopenharmony_ci if (rear_switch) { 185362306a36Sopenharmony_ci err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_ymfpci_rear_shared, chip)); 185462306a36Sopenharmony_ci if (err < 0) 185562306a36Sopenharmony_ci return err; 185662306a36Sopenharmony_ci } 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci /* per-voice volume */ 185962306a36Sopenharmony_ci substream = chip->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 186062306a36Sopenharmony_ci for (idx = 0; idx < 32; ++idx) { 186162306a36Sopenharmony_ci kctl = snd_ctl_new1(&snd_ymfpci_pcm_volume, chip); 186262306a36Sopenharmony_ci if (!kctl) 186362306a36Sopenharmony_ci return -ENOMEM; 186462306a36Sopenharmony_ci kctl->id.device = chip->pcm->device; 186562306a36Sopenharmony_ci kctl->id.subdevice = idx; 186662306a36Sopenharmony_ci kctl->private_value = (unsigned long)substream; 186762306a36Sopenharmony_ci err = snd_ctl_add(chip->card, kctl); 186862306a36Sopenharmony_ci if (err < 0) 186962306a36Sopenharmony_ci return err; 187062306a36Sopenharmony_ci chip->pcm_mixer[idx].left = 0x8000; 187162306a36Sopenharmony_ci chip->pcm_mixer[idx].right = 0x8000; 187262306a36Sopenharmony_ci chip->pcm_mixer[idx].ctl = kctl; 187362306a36Sopenharmony_ci substream = substream->next; 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci return 0; 187762306a36Sopenharmony_ci} 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci/* 188162306a36Sopenharmony_ci * timer 188262306a36Sopenharmony_ci */ 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_cistatic int snd_ymfpci_timer_start(struct snd_timer *timer) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct snd_ymfpci *chip; 188762306a36Sopenharmony_ci unsigned long flags; 188862306a36Sopenharmony_ci unsigned int count; 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci chip = snd_timer_chip(timer); 189162306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 189262306a36Sopenharmony_ci if (timer->sticks > 1) { 189362306a36Sopenharmony_ci chip->timer_ticks = timer->sticks; 189462306a36Sopenharmony_ci count = timer->sticks - 1; 189562306a36Sopenharmony_ci } else { 189662306a36Sopenharmony_ci /* 189762306a36Sopenharmony_ci * Divisor 1 is not allowed; fake it by using divisor 2 and 189862306a36Sopenharmony_ci * counting two ticks for each interrupt. 189962306a36Sopenharmony_ci */ 190062306a36Sopenharmony_ci chip->timer_ticks = 2; 190162306a36Sopenharmony_ci count = 2 - 1; 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_TIMERCOUNT, count); 190462306a36Sopenharmony_ci snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x03); 190562306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 190662306a36Sopenharmony_ci return 0; 190762306a36Sopenharmony_ci} 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_cistatic int snd_ymfpci_timer_stop(struct snd_timer *timer) 191062306a36Sopenharmony_ci{ 191162306a36Sopenharmony_ci struct snd_ymfpci *chip; 191262306a36Sopenharmony_ci unsigned long flags; 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci chip = snd_timer_chip(timer); 191562306a36Sopenharmony_ci spin_lock_irqsave(&chip->reg_lock, flags); 191662306a36Sopenharmony_ci snd_ymfpci_writeb(chip, YDSXGR_TIMERCTRL, 0x00); 191762306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->reg_lock, flags); 191862306a36Sopenharmony_ci return 0; 191962306a36Sopenharmony_ci} 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_cistatic int snd_ymfpci_timer_precise_resolution(struct snd_timer *timer, 192262306a36Sopenharmony_ci unsigned long *num, unsigned long *den) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci *num = 1; 192562306a36Sopenharmony_ci *den = 96000; 192662306a36Sopenharmony_ci return 0; 192762306a36Sopenharmony_ci} 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_cistatic const struct snd_timer_hardware snd_ymfpci_timer_hw = { 193062306a36Sopenharmony_ci .flags = SNDRV_TIMER_HW_AUTO, 193162306a36Sopenharmony_ci .resolution = 10417, /* 1 / 96 kHz = 10.41666...us */ 193262306a36Sopenharmony_ci .ticks = 0x10000, 193362306a36Sopenharmony_ci .start = snd_ymfpci_timer_start, 193462306a36Sopenharmony_ci .stop = snd_ymfpci_timer_stop, 193562306a36Sopenharmony_ci .precise_resolution = snd_ymfpci_timer_precise_resolution, 193662306a36Sopenharmony_ci}; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ciint snd_ymfpci_timer(struct snd_ymfpci *chip, int device) 193962306a36Sopenharmony_ci{ 194062306a36Sopenharmony_ci struct snd_timer *timer = NULL; 194162306a36Sopenharmony_ci struct snd_timer_id tid; 194262306a36Sopenharmony_ci int err; 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci tid.dev_class = SNDRV_TIMER_CLASS_CARD; 194562306a36Sopenharmony_ci tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; 194662306a36Sopenharmony_ci tid.card = chip->card->number; 194762306a36Sopenharmony_ci tid.device = device; 194862306a36Sopenharmony_ci tid.subdevice = 0; 194962306a36Sopenharmony_ci err = snd_timer_new(chip->card, "YMFPCI", &tid, &timer); 195062306a36Sopenharmony_ci if (err >= 0) { 195162306a36Sopenharmony_ci strcpy(timer->name, "YMFPCI timer"); 195262306a36Sopenharmony_ci timer->private_data = chip; 195362306a36Sopenharmony_ci timer->hw = snd_ymfpci_timer_hw; 195462306a36Sopenharmony_ci } 195562306a36Sopenharmony_ci chip->timer = timer; 195662306a36Sopenharmony_ci return err; 195762306a36Sopenharmony_ci} 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci/* 196162306a36Sopenharmony_ci * proc interface 196262306a36Sopenharmony_ci */ 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_cistatic void snd_ymfpci_proc_read(struct snd_info_entry *entry, 196562306a36Sopenharmony_ci struct snd_info_buffer *buffer) 196662306a36Sopenharmony_ci{ 196762306a36Sopenharmony_ci struct snd_ymfpci *chip = entry->private_data; 196862306a36Sopenharmony_ci int i; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci snd_iprintf(buffer, "YMFPCI\n\n"); 197162306a36Sopenharmony_ci for (i = 0; i <= YDSXGR_WORKBASE; i += 4) 197262306a36Sopenharmony_ci snd_iprintf(buffer, "%04x: %04x\n", i, snd_ymfpci_readl(chip, i)); 197362306a36Sopenharmony_ci} 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_cistatic int snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip) 197662306a36Sopenharmony_ci{ 197762306a36Sopenharmony_ci return snd_card_ro_proc_new(card, "ymfpci", chip, snd_ymfpci_proc_read); 197862306a36Sopenharmony_ci} 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci/* 198162306a36Sopenharmony_ci * initialization routines 198262306a36Sopenharmony_ci */ 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_cistatic void snd_ymfpci_aclink_reset(struct pci_dev * pci) 198562306a36Sopenharmony_ci{ 198662306a36Sopenharmony_ci u8 cmd; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci pci_read_config_byte(pci, PCIR_DSXG_CTRL, &cmd); 198962306a36Sopenharmony_ci#if 0 // force to reset 199062306a36Sopenharmony_ci if (cmd & 0x03) { 199162306a36Sopenharmony_ci#endif 199262306a36Sopenharmony_ci pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc); 199362306a36Sopenharmony_ci pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd | 0x03); 199462306a36Sopenharmony_ci pci_write_config_byte(pci, PCIR_DSXG_CTRL, cmd & 0xfc); 199562306a36Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_PWRCTRL1, 0); 199662306a36Sopenharmony_ci pci_write_config_word(pci, PCIR_DSXG_PWRCTRL2, 0); 199762306a36Sopenharmony_ci#if 0 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci#endif 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_cistatic void snd_ymfpci_enable_dsp(struct snd_ymfpci *chip) 200362306a36Sopenharmony_ci{ 200462306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000001); 200562306a36Sopenharmony_ci} 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_cistatic void snd_ymfpci_disable_dsp(struct snd_ymfpci *chip) 200862306a36Sopenharmony_ci{ 200962306a36Sopenharmony_ci u32 val; 201062306a36Sopenharmony_ci int timeout = 1000; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci val = snd_ymfpci_readl(chip, YDSXGR_CONFIG); 201362306a36Sopenharmony_ci if (val) 201462306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_CONFIG, 0x00000000); 201562306a36Sopenharmony_ci while (timeout-- > 0) { 201662306a36Sopenharmony_ci val = snd_ymfpci_readl(chip, YDSXGR_STATUS); 201762306a36Sopenharmony_ci if ((val & 0x00000002) == 0) 201862306a36Sopenharmony_ci break; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_cistatic int snd_ymfpci_request_firmware(struct snd_ymfpci *chip) 202362306a36Sopenharmony_ci{ 202462306a36Sopenharmony_ci int err, is_1e; 202562306a36Sopenharmony_ci const char *name; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw", 202862306a36Sopenharmony_ci &chip->pci->dev); 202962306a36Sopenharmony_ci if (err >= 0) { 203062306a36Sopenharmony_ci if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) { 203162306a36Sopenharmony_ci dev_err(chip->card->dev, 203262306a36Sopenharmony_ci "DSP microcode has wrong size\n"); 203362306a36Sopenharmony_ci err = -EINVAL; 203462306a36Sopenharmony_ci } 203562306a36Sopenharmony_ci } 203662306a36Sopenharmony_ci if (err < 0) 203762306a36Sopenharmony_ci return err; 203862306a36Sopenharmony_ci is_1e = chip->device_id == PCI_DEVICE_ID_YAMAHA_724F || 203962306a36Sopenharmony_ci chip->device_id == PCI_DEVICE_ID_YAMAHA_740C || 204062306a36Sopenharmony_ci chip->device_id == PCI_DEVICE_ID_YAMAHA_744 || 204162306a36Sopenharmony_ci chip->device_id == PCI_DEVICE_ID_YAMAHA_754; 204262306a36Sopenharmony_ci name = is_1e ? "yamaha/ds1e_ctrl.fw" : "yamaha/ds1_ctrl.fw"; 204362306a36Sopenharmony_ci err = request_firmware(&chip->controller_microcode, name, 204462306a36Sopenharmony_ci &chip->pci->dev); 204562306a36Sopenharmony_ci if (err >= 0) { 204662306a36Sopenharmony_ci if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) { 204762306a36Sopenharmony_ci dev_err(chip->card->dev, 204862306a36Sopenharmony_ci "controller microcode has wrong size\n"); 204962306a36Sopenharmony_ci err = -EINVAL; 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci if (err < 0) 205362306a36Sopenharmony_ci return err; 205462306a36Sopenharmony_ci return 0; 205562306a36Sopenharmony_ci} 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1_dsp.fw"); 205862306a36Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1_ctrl.fw"); 205962306a36Sopenharmony_ciMODULE_FIRMWARE("yamaha/ds1e_ctrl.fw"); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_cistatic void snd_ymfpci_download_image(struct snd_ymfpci *chip) 206262306a36Sopenharmony_ci{ 206362306a36Sopenharmony_ci int i; 206462306a36Sopenharmony_ci u16 ctrl; 206562306a36Sopenharmony_ci const __le32 *inst; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000); 206862306a36Sopenharmony_ci snd_ymfpci_disable_dsp(chip); 206962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00010000); 207062306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, 0x00000000); 207162306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MAPOFREC, 0x00000000); 207262306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MAPOFEFFECT, 0x00000000); 207362306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0x00000000); 207462306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0x00000000); 207562306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0x00000000); 207662306a36Sopenharmony_ci ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); 207762306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci /* setup DSP instruction code */ 208062306a36Sopenharmony_ci inst = (const __le32 *)chip->dsp_microcode->data; 208162306a36Sopenharmony_ci for (i = 0; i < YDSXG_DSPLENGTH / 4; i++) 208262306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), 208362306a36Sopenharmony_ci le32_to_cpu(inst[i])); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci /* setup control instruction code */ 208662306a36Sopenharmony_ci inst = (const __le32 *)chip->controller_microcode->data; 208762306a36Sopenharmony_ci for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++) 208862306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), 208962306a36Sopenharmony_ci le32_to_cpu(inst[i])); 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci snd_ymfpci_enable_dsp(chip); 209262306a36Sopenharmony_ci} 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_cistatic int snd_ymfpci_memalloc(struct snd_ymfpci *chip) 209562306a36Sopenharmony_ci{ 209662306a36Sopenharmony_ci long size, playback_ctrl_size; 209762306a36Sopenharmony_ci int voice, bank, reg; 209862306a36Sopenharmony_ci u8 *ptr; 209962306a36Sopenharmony_ci dma_addr_t ptr_addr; 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_ci playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES; 210262306a36Sopenharmony_ci chip->bank_size_playback = snd_ymfpci_readl(chip, YDSXGR_PLAYCTRLSIZE) << 2; 210362306a36Sopenharmony_ci chip->bank_size_capture = snd_ymfpci_readl(chip, YDSXGR_RECCTRLSIZE) << 2; 210462306a36Sopenharmony_ci chip->bank_size_effect = snd_ymfpci_readl(chip, YDSXGR_EFFCTRLSIZE) << 2; 210562306a36Sopenharmony_ci chip->work_size = YDSXG_DEFAULT_WORK_SIZE; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci size = ALIGN(playback_ctrl_size, 0x100) + 210862306a36Sopenharmony_ci ALIGN(chip->bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES, 0x100) + 210962306a36Sopenharmony_ci ALIGN(chip->bank_size_capture * 2 * YDSXG_CAPTURE_VOICES, 0x100) + 211062306a36Sopenharmony_ci ALIGN(chip->bank_size_effect * 2 * YDSXG_EFFECT_VOICES, 0x100) + 211162306a36Sopenharmony_ci chip->work_size; 211262306a36Sopenharmony_ci /* work_ptr must be aligned to 256 bytes, but it's already 211362306a36Sopenharmony_ci covered with the kernel page allocation mechanism */ 211462306a36Sopenharmony_ci chip->work_ptr = snd_devm_alloc_pages(&chip->pci->dev, 211562306a36Sopenharmony_ci SNDRV_DMA_TYPE_DEV, size); 211662306a36Sopenharmony_ci if (!chip->work_ptr) 211762306a36Sopenharmony_ci return -ENOMEM; 211862306a36Sopenharmony_ci ptr = chip->work_ptr->area; 211962306a36Sopenharmony_ci ptr_addr = chip->work_ptr->addr; 212062306a36Sopenharmony_ci memset(ptr, 0, size); /* for sure */ 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci chip->bank_base_playback = ptr; 212362306a36Sopenharmony_ci chip->bank_base_playback_addr = ptr_addr; 212462306a36Sopenharmony_ci chip->ctrl_playback = (__le32 *)ptr; 212562306a36Sopenharmony_ci chip->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES); 212662306a36Sopenharmony_ci ptr += ALIGN(playback_ctrl_size, 0x100); 212762306a36Sopenharmony_ci ptr_addr += ALIGN(playback_ctrl_size, 0x100); 212862306a36Sopenharmony_ci for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) { 212962306a36Sopenharmony_ci chip->voices[voice].number = voice; 213062306a36Sopenharmony_ci chip->voices[voice].bank = (struct snd_ymfpci_playback_bank *)ptr; 213162306a36Sopenharmony_ci chip->voices[voice].bank_addr = ptr_addr; 213262306a36Sopenharmony_ci for (bank = 0; bank < 2; bank++) { 213362306a36Sopenharmony_ci chip->bank_playback[voice][bank] = (struct snd_ymfpci_playback_bank *)ptr; 213462306a36Sopenharmony_ci ptr += chip->bank_size_playback; 213562306a36Sopenharmony_ci ptr_addr += chip->bank_size_playback; 213662306a36Sopenharmony_ci } 213762306a36Sopenharmony_ci } 213862306a36Sopenharmony_ci ptr = (char *)ALIGN((unsigned long)ptr, 0x100); 213962306a36Sopenharmony_ci ptr_addr = ALIGN(ptr_addr, 0x100); 214062306a36Sopenharmony_ci chip->bank_base_capture = ptr; 214162306a36Sopenharmony_ci chip->bank_base_capture_addr = ptr_addr; 214262306a36Sopenharmony_ci for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++) 214362306a36Sopenharmony_ci for (bank = 0; bank < 2; bank++) { 214462306a36Sopenharmony_ci chip->bank_capture[voice][bank] = (struct snd_ymfpci_capture_bank *)ptr; 214562306a36Sopenharmony_ci ptr += chip->bank_size_capture; 214662306a36Sopenharmony_ci ptr_addr += chip->bank_size_capture; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci ptr = (char *)ALIGN((unsigned long)ptr, 0x100); 214962306a36Sopenharmony_ci ptr_addr = ALIGN(ptr_addr, 0x100); 215062306a36Sopenharmony_ci chip->bank_base_effect = ptr; 215162306a36Sopenharmony_ci chip->bank_base_effect_addr = ptr_addr; 215262306a36Sopenharmony_ci for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++) 215362306a36Sopenharmony_ci for (bank = 0; bank < 2; bank++) { 215462306a36Sopenharmony_ci chip->bank_effect[voice][bank] = (struct snd_ymfpci_effect_bank *)ptr; 215562306a36Sopenharmony_ci ptr += chip->bank_size_effect; 215662306a36Sopenharmony_ci ptr_addr += chip->bank_size_effect; 215762306a36Sopenharmony_ci } 215862306a36Sopenharmony_ci ptr = (char *)ALIGN((unsigned long)ptr, 0x100); 215962306a36Sopenharmony_ci ptr_addr = ALIGN(ptr_addr, 0x100); 216062306a36Sopenharmony_ci chip->work_base = ptr; 216162306a36Sopenharmony_ci chip->work_base_addr = ptr_addr; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci snd_BUG_ON(ptr + PAGE_ALIGN(chip->work_size) != 216462306a36Sopenharmony_ci chip->work_ptr->area + chip->work_ptr->bytes); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr); 216762306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr); 216862306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, chip->bank_base_effect_addr); 216962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_WORKBASE, chip->work_base_addr); 217062306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, chip->work_size >> 2); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci /* S/PDIF output initialization */ 217362306a36Sopenharmony_ci chip->spdif_bits = chip->spdif_pcm_bits = SNDRV_PCM_DEFAULT_CON_SPDIF & 0xffff; 217462306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTCTRL, 0); 217562306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFOUTSTATUS, chip->spdif_bits); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci /* S/PDIF input initialization */ 217862306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_SPDIFINCTRL, 0); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci /* digital mixer setup */ 218162306a36Sopenharmony_ci for (reg = 0x80; reg < 0xc0; reg += 4) 218262306a36Sopenharmony_ci snd_ymfpci_writel(chip, reg, 0); 218362306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff); 218462306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff); 218562306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff); 218662306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff); 218762306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff); 218862306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_NATIVEDACINVOL, 0x3fff3fff); 218962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_PRIADCLOOPVOL, 0x3fff3fff); 219062306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0x3fff3fff); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci return 0; 219362306a36Sopenharmony_ci} 219462306a36Sopenharmony_ci 219562306a36Sopenharmony_cistatic void snd_ymfpci_free(struct snd_card *card) 219662306a36Sopenharmony_ci{ 219762306a36Sopenharmony_ci struct snd_ymfpci *chip = card->private_data; 219862306a36Sopenharmony_ci u16 ctrl; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); 220162306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); 220262306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_LEGACYOUTVOL, 0); 220362306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_STATUS, ~0); 220462306a36Sopenharmony_ci snd_ymfpci_disable_dsp(chip); 220562306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, 0); 220662306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, 0); 220762306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_EFFCTRLBASE, 0); 220862306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_WORKBASE, 0); 220962306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_WORKSIZE, 0); 221062306a36Sopenharmony_ci ctrl = snd_ymfpci_readw(chip, YDSXGR_GLOBALCTRL); 221162306a36Sopenharmony_ci snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci snd_ymfpci_ac3_done(chip); 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci snd_ymfpci_free_gameport(chip); 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, chip->old_legacy_ctrl); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci release_firmware(chip->dsp_microcode); 222062306a36Sopenharmony_ci release_firmware(chip->controller_microcode); 222162306a36Sopenharmony_ci} 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_cistatic int snd_ymfpci_suspend(struct device *dev) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 222662306a36Sopenharmony_ci struct snd_ymfpci *chip = card->private_data; 222762306a36Sopenharmony_ci unsigned int i, legacy_reg_count = DSXG_PCI_NUM_SAVED_LEGACY_REGS; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci if (chip->pci->device >= 0x0010) /* YMF 744/754 */ 223062306a36Sopenharmony_ci legacy_reg_count = DSXG_PCI_NUM_SAVED_REGS; 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 223362306a36Sopenharmony_ci snd_ac97_suspend(chip->ac97); 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) 223662306a36Sopenharmony_ci chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci for (i = 0; i < legacy_reg_count; i++) 224162306a36Sopenharmony_ci pci_read_config_word(chip->pci, pci_saved_regs_index[i], 224262306a36Sopenharmony_ci chip->saved_dsxg_pci_regs + i); 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); 224562306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); 224662306a36Sopenharmony_ci snd_ymfpci_disable_dsp(chip); 224762306a36Sopenharmony_ci return 0; 224862306a36Sopenharmony_ci} 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_cistatic int snd_ymfpci_resume(struct device *dev) 225162306a36Sopenharmony_ci{ 225262306a36Sopenharmony_ci struct pci_dev *pci = to_pci_dev(dev); 225362306a36Sopenharmony_ci struct snd_card *card = dev_get_drvdata(dev); 225462306a36Sopenharmony_ci struct snd_ymfpci *chip = card->private_data; 225562306a36Sopenharmony_ci unsigned int i, legacy_reg_count = DSXG_PCI_NUM_SAVED_LEGACY_REGS; 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci if (chip->pci->device >= 0x0010) /* YMF 744/754 */ 225862306a36Sopenharmony_ci legacy_reg_count = DSXG_PCI_NUM_SAVED_REGS; 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci snd_ymfpci_aclink_reset(pci); 226162306a36Sopenharmony_ci snd_ymfpci_codec_ready(chip, 0); 226262306a36Sopenharmony_ci snd_ymfpci_download_image(chip); 226362306a36Sopenharmony_ci udelay(100); 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) 226662306a36Sopenharmony_ci snd_ymfpci_writel(chip, saved_regs_index[i], chip->saved_regs[i]); 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci snd_ac97_resume(chip->ac97); 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci for (i = 0; i < legacy_reg_count; i++) 227162306a36Sopenharmony_ci pci_write_config_word(chip->pci, pci_saved_regs_index[i], 227262306a36Sopenharmony_ci chip->saved_dsxg_pci_regs[i]); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci /* start hw again */ 227562306a36Sopenharmony_ci if (chip->start_count > 0) { 227662306a36Sopenharmony_ci spin_lock_irq(&chip->reg_lock); 227762306a36Sopenharmony_ci snd_ymfpci_writel(chip, YDSXGR_MODE, chip->saved_ydsxgr_mode); 227862306a36Sopenharmony_ci chip->active_bank = snd_ymfpci_readl(chip, YDSXGR_CTRLSELECT); 227962306a36Sopenharmony_ci spin_unlock_irq(&chip->reg_lock); 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci snd_power_change_state(card, SNDRV_CTL_POWER_D0); 228262306a36Sopenharmony_ci return 0; 228362306a36Sopenharmony_ci} 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ciDEFINE_SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ciint snd_ymfpci_create(struct snd_card *card, 228862306a36Sopenharmony_ci struct pci_dev *pci, 228962306a36Sopenharmony_ci u16 old_legacy_ctrl) 229062306a36Sopenharmony_ci{ 229162306a36Sopenharmony_ci struct snd_ymfpci *chip = card->private_data; 229262306a36Sopenharmony_ci int err; 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci /* enable PCI device */ 229562306a36Sopenharmony_ci err = pcim_enable_device(pci); 229662306a36Sopenharmony_ci if (err < 0) 229762306a36Sopenharmony_ci return err; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci chip->old_legacy_ctrl = old_legacy_ctrl; 230062306a36Sopenharmony_ci spin_lock_init(&chip->reg_lock); 230162306a36Sopenharmony_ci spin_lock_init(&chip->voice_lock); 230262306a36Sopenharmony_ci init_waitqueue_head(&chip->interrupt_sleep); 230362306a36Sopenharmony_ci atomic_set(&chip->interrupt_sleep_count, 0); 230462306a36Sopenharmony_ci chip->card = card; 230562306a36Sopenharmony_ci chip->pci = pci; 230662306a36Sopenharmony_ci chip->irq = -1; 230762306a36Sopenharmony_ci chip->device_id = pci->device; 230862306a36Sopenharmony_ci chip->rev = pci->revision; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci err = pci_request_regions(pci, "YMFPCI"); 231162306a36Sopenharmony_ci if (err < 0) 231262306a36Sopenharmony_ci return err; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_ci chip->reg_area_phys = pci_resource_start(pci, 0); 231562306a36Sopenharmony_ci chip->reg_area_virt = devm_ioremap(&pci->dev, chip->reg_area_phys, 0x8000); 231662306a36Sopenharmony_ci if (!chip->reg_area_virt) { 231762306a36Sopenharmony_ci dev_err(chip->card->dev, 231862306a36Sopenharmony_ci "unable to grab memory region 0x%lx-0x%lx\n", 231962306a36Sopenharmony_ci chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); 232062306a36Sopenharmony_ci return -EBUSY; 232162306a36Sopenharmony_ci } 232262306a36Sopenharmony_ci pci_set_master(pci); 232362306a36Sopenharmony_ci chip->src441_used = -1; 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci if (devm_request_irq(&pci->dev, pci->irq, snd_ymfpci_interrupt, IRQF_SHARED, 232662306a36Sopenharmony_ci KBUILD_MODNAME, chip)) { 232762306a36Sopenharmony_ci dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq); 232862306a36Sopenharmony_ci return -EBUSY; 232962306a36Sopenharmony_ci } 233062306a36Sopenharmony_ci chip->irq = pci->irq; 233162306a36Sopenharmony_ci card->sync_irq = chip->irq; 233262306a36Sopenharmony_ci card->private_free = snd_ymfpci_free; 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci snd_ymfpci_aclink_reset(pci); 233562306a36Sopenharmony_ci if (snd_ymfpci_codec_ready(chip, 0) < 0) 233662306a36Sopenharmony_ci return -EIO; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci err = snd_ymfpci_request_firmware(chip); 233962306a36Sopenharmony_ci if (err < 0) { 234062306a36Sopenharmony_ci dev_err(chip->card->dev, "firmware request failed: %d\n", err); 234162306a36Sopenharmony_ci return err; 234262306a36Sopenharmony_ci } 234362306a36Sopenharmony_ci snd_ymfpci_download_image(chip); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci udelay(100); /* seems we need a delay after downloading image.. */ 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci if (snd_ymfpci_memalloc(chip) < 0) 234862306a36Sopenharmony_ci return -EIO; 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci err = snd_ymfpci_ac3_init(chip); 235162306a36Sopenharmony_ci if (err < 0) 235262306a36Sopenharmony_ci return err; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci snd_ymfpci_proc_init(card, chip); 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci return 0; 235762306a36Sopenharmony_ci} 2358