/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
* Routines for control of YMF724/740/744/754 chips
*
* This program is free software; you can redistribute it and/or modify
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/control.h>
do {
if ((snd_ymfpci_readw(chip, reg) & 0x8000) == 0)
return 0;
- set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout_uninterruptible(1);
} while (time_before(jiffies, end_time));
snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg));
return val[0];
}
-static void snd_ymfpci_pcm_441_volume_set(struct snd_ymfpci_pcm *ypcm)
-{
- unsigned int value;
- struct snd_ymfpci_pcm_mixer *mixer;
-
- mixer = &ypcm->chip->pcm_mixer[ypcm->substream->number];
- value = min_t(unsigned int, mixer->left, 0x7fff) >> 1;
- value |= (min_t(unsigned int, mixer->right, 0x7fff) >> 1) << 16;
- snd_ymfpci_writel(ypcm->chip, YDSXGR_BUF441OUTVOL, value);
-}
-
/*
* Hardware start management
*/
unsigned long flags;
int result;
- snd_assert(rvoice != NULL, return -EINVAL);
- snd_assert(!pair || type == YMFPCI_PCM, return -EINVAL);
+ if (snd_BUG_ON(!rvoice))
+ return -EINVAL;
+ if (snd_BUG_ON(pair && type != YMFPCI_PCM))
+ return -EINVAL;
spin_lock_irqsave(&chip->voice_lock, flags);
for (;;) {
{
unsigned long flags;
- snd_assert(pvoice != NULL, return -EINVAL);
+ if (snd_BUG_ON(!pvoice))
+ return -EINVAL;
snd_ymfpci_hw_stop(chip);
spin_lock_irqsave(&chip->voice_lock, flags);
if (pvoice->number == chip->src441_used) {
{
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
+ struct snd_kcontrol *kctl = NULL;
int result = 0;
spin_lock(&chip->reg_lock);
ypcm->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
+ if (substream->pcm == chip->pcm && !ypcm->use_441_slot) {
+ kctl = chip->pcm_mixer[substream->number].ctl;
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ }
+ /* fall through */
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
chip->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
}
__unlock:
spin_unlock(&chip->reg_lock);
+ if (kctl)
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return result;
}
static int snd_ymfpci_capture_trigger(struct snd_pcm_substream *substream,
u8 use_left, use_right;
unsigned long flags;
- snd_assert(voice != NULL, return);
+ if (snd_BUG_ON(!voice))
+ return;
if (runtime->channels == 1) {
use_left = 1;
use_right = 1;
ypcm->chip->src441_used = voice->number;
ypcm->use_441_slot = 1;
format |= 0x10000000;
- snd_ymfpci_pcm_441_volume_set(ypcm);
}
if (ypcm->chip->src441_used == voice->number &&
(format & 0x10000000) == 0) {
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ymfpci_pcm *ypcm = runtime->private_data;
+ struct snd_kcontrol *kctl;
unsigned int nvoice;
ypcm->period_size = runtime->period_size;
for (nvoice = 0; nvoice < runtime->channels; nvoice++)
snd_ymfpci_pcm_init_voice(ypcm, nvoice, runtime,
substream->pcm == chip->pcm);
+
+ if (substream->pcm == chip->pcm && !ypcm->use_441_slot) {
+ kctl = chip->pcm_mixer[substream->number].ctl;
+ kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
+ }
return 0;
}
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ymfpci_pcm *ypcm;
- struct snd_kcontrol *kctl;
int err;
if ((err = snd_ymfpci_playback_open_1(substream)) < 0)
chip->rear_opened++;
}
spin_unlock_irq(&chip->reg_lock);
-
- kctl = chip->pcm_mixer[substream->number].ctl;
- kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return 0;
}
{
struct snd_ymfpci *chip = snd_pcm_substream_chip(substream);
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
- struct snd_kcontrol *kctl;
spin_lock_irq(&chip->reg_lock);
if (ypcm->output_rear && chip->rear_opened > 0) {
ymfpci_close_extension(chip);
}
spin_unlock_irq(&chip->reg_lock);
- kctl = chip->pcm_mixer[substream->number].ctl;
- kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
- snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id);
return snd_ymfpci_playback_close_1(substream);
}
.get = snd_ymfpci_get_single, .put = snd_ymfpci_put_single, \
.private_value = ((reg) | ((shift) << 16)) }
-static int snd_ymfpci_info_single(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- int reg = kcontrol->private_value & 0xffff;
-
- switch (reg) {
- case YDSXGR_SPDIFOUTCTRL: break;
- case YDSXGR_SPDIFINCTRL: break;
- default: return -EINVAL;
- }
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_ymfpci_info_single snd_ctl_boolean_mono_info
static int snd_ymfpci_get_single(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
return change;
}
+static int snd_ymfpci_put_nativedacvol(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_ymfpci *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = YDSXGR_NATIVEDACOUTVOL;
+ unsigned int reg2 = YDSXGR_BUF441OUTVOL;
+ int change;
+ unsigned int value, oval;
+
+ value = ucontrol->value.integer.value[0] & 0x3fff;
+ value |= (ucontrol->value.integer.value[1] & 0x3fff) << 16;
+ spin_lock_irq(&chip->reg_lock);
+ oval = snd_ymfpci_readl(chip, reg);
+ change = value != oval;
+ snd_ymfpci_writel(chip, reg, value);
+ snd_ymfpci_writel(chip, reg2, value);
+ spin_unlock_irq(&chip->reg_lock);
+ return change;
+}
+
/*
* 4ch duplication
*/
-static int snd_ymfpci_info_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_ymfpci_info_dup4ch snd_ctl_boolean_mono_info
static int snd_ymfpci_get_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
static struct snd_kcontrol_new snd_ymfpci_controls[] __devinitdata = {
-YMFPCI_DOUBLE("Wave Playback Volume", 0, YDSXGR_NATIVEDACOUTVOL),
+{
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Wave Playback Volume",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .info = snd_ymfpci_info_double,
+ .get = snd_ymfpci_get_double,
+ .put = snd_ymfpci_put_nativedacvol,
+ .private_value = YDSXGR_NATIVEDACOUTVOL,
+ .tlv = { .p = db_scale_native },
+},
YMFPCI_DOUBLE("Wave Capture Volume", 0, YDSXGR_NATIVEDACLOOPVOL),
YMFPCI_DOUBLE("Digital Capture Volume", 0, YDSXGR_NATIVEDACINVOL),
YMFPCI_DOUBLE("Digital Capture Volume", 1, YDSXGR_NATIVEADCINVOL),
return 0;
}
-static int snd_ymfpci_gpio_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 1;
- return 0;
-}
+#define snd_ymfpci_gpio_sw_info snd_ctl_boolean_mono_info
static int snd_ymfpci_gpio_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[1] != chip->pcm_mixer[subs].right) {
chip->pcm_mixer[subs].left = ucontrol->value.integer.value[0];
chip->pcm_mixer[subs].right = ucontrol->value.integer.value[1];
+ if (chip->pcm_mixer[subs].left > 0x8000)
+ chip->pcm_mixer[subs].left = 0x8000;
+ if (chip->pcm_mixer[subs].right > 0x8000)
+ chip->pcm_mixer[subs].right = 0x8000;
substream = (struct snd_pcm_substream *)kcontrol->private_value;
spin_lock_irqsave(&chip->voice_lock, flags);
struct snd_ymfpci_pcm *ypcm = substream->runtime->private_data;
if (!ypcm->use_441_slot)
ypcm->update_pcm_vol = 2;
- else
- snd_ymfpci_pcm_441_volume_set(ypcm);
}
spin_unlock_irqrestore(&chip->voice_lock, flags);
return 1;
}
/* add S/PDIF control */
- snd_assert(chip->pcm_spdif != NULL, return -EIO);
+ if (snd_BUG_ON(!chip->pcm_spdif))
+ return -ENXIO;
if ((err = snd_ctl_add(chip->card, kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip))) < 0)
return err;
kctl->id.device = chip->pcm_spdif->device;
}
}
-#ifdef CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL
-
-#include "ymfpci_image.h"
-
-static struct firmware snd_ymfpci_dsp_microcode = {
- .size = YDSXG_DSPLENGTH,
- .data = (u8 *)DspInst,
-};
-static struct firmware snd_ymfpci_controller_microcode = {
- .size = YDSXG_CTRLLENGTH,
- .data = (u8 *)CntrlInst,
-};
-static struct firmware snd_ymfpci_controller_1e_microcode = {
- .size = YDSXG_CTRLLENGTH,
- .data = (u8 *)CntrlInst1E,
-};
-#endif
-
-#ifdef CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL
-static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
-{
- chip->dsp_microcode = &snd_ymfpci_dsp_microcode;
- if (chip->device_id == PCI_DEVICE_ID_YAMAHA_724F ||
- chip->device_id == PCI_DEVICE_ID_YAMAHA_740C ||
- chip->device_id == PCI_DEVICE_ID_YAMAHA_744 ||
- chip->device_id == PCI_DEVICE_ID_YAMAHA_754)
- chip->controller_microcode =
- &snd_ymfpci_controller_1e_microcode;
- else
- chip->controller_microcode =
- &snd_ymfpci_controller_microcode;
- return 0;
-}
-
-#else /* use fw_loader */
-
-#ifdef __LITTLE_ENDIAN
-static inline void snd_ymfpci_convert_from_le(const struct firmware *fw) { }
-#else
-static void snd_ymfpci_convert_from_le(const struct firmware *fw)
-{
- int i;
- u32 *data = (u32 *)fw->data;
-
- for (i = 0; i < fw->size / 4; ++i)
- le32_to_cpus(&data[i]);
-}
-#endif
-
static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip)
{
int err, is_1e;
err = request_firmware(&chip->dsp_microcode, "yamaha/ds1_dsp.fw",
&chip->pci->dev);
if (err >= 0) {
- if (chip->dsp_microcode->size == YDSXG_DSPLENGTH)
- snd_ymfpci_convert_from_le(chip->dsp_microcode);
- else {
+ if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) {
snd_printk(KERN_ERR "DSP microcode has wrong size\n");
err = -EINVAL;
}
err = request_firmware(&chip->controller_microcode, name,
&chip->pci->dev);
if (err >= 0) {
- if (chip->controller_microcode->size == YDSXG_CTRLLENGTH)
- snd_ymfpci_convert_from_le(chip->controller_microcode);
- else {
+ if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) {
snd_printk(KERN_ERR "controller microcode"
" has wrong size\n");
err = -EINVAL;
MODULE_FIRMWARE("yamaha/ds1_ctrl.fw");
MODULE_FIRMWARE("yamaha/ds1e_ctrl.fw");
-#endif
-
static void snd_ymfpci_download_image(struct snd_ymfpci *chip)
{
int i;
u16 ctrl;
- u32 *inst;
+ const __le32 *inst;
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
snd_ymfpci_disable_dsp(chip);
snd_ymfpci_writew(chip, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
/* setup DSP instruction code */
- inst = (u32 *)chip->dsp_microcode->data;
+ inst = (const __le32 *)chip->dsp_microcode->data;
for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
- snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2), inst[i]);
+ snd_ymfpci_writel(chip, YDSXGR_DSPINSTRAM + (i << 2),
+ le32_to_cpu(inst[i]));
/* setup control instruction code */
- inst = (u32 *)chip->controller_microcode->data;
+ inst = (const __le32 *)chip->controller_microcode->data;
for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
- snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2), inst[i]);
+ snd_ymfpci_writel(chip, YDSXGR_CTRLINSTRAM + (i << 2),
+ le32_to_cpu(inst[i]));
snd_ymfpci_enable_dsp(chip);
}
chip->work_base = ptr;
chip->work_base_addr = ptr_addr;
- snd_assert(ptr + chip->work_size == chip->work_ptr.area + chip->work_ptr.bytes, );
+ snd_BUG_ON(ptr + chip->work_size !=
+ chip->work_ptr.area + chip->work_ptr.bytes);
snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr);
snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr);
for (reg = 0x80; reg < 0xc0; reg += 4)
snd_ymfpci_writel(chip, reg, 0);
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
+ snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0x3fff3fff);
snd_ymfpci_writel(chip, YDSXGR_ZVOUTVOL, 0x3fff3fff);
snd_ymfpci_writel(chip, YDSXGR_SPDIFOUTVOL, 0x3fff3fff);
snd_ymfpci_writel(chip, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
{
u16 ctrl;
- snd_assert(chip != NULL, return -EINVAL);
+ if (snd_BUG_ON(!chip))
+ return -EINVAL;
if (chip->res_reg_area) { /* don't touch busy hardware */
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
#ifdef CONFIG_PM
vfree(chip->saved_regs);
#endif
+ if (chip->irq >= 0)
+ free_irq(chip->irq, chip);
release_and_free_resource(chip->mpu_res);
release_and_free_resource(chip->fm_res);
snd_ymfpci_free_gameport(chip);
if (chip->work_ptr.area)
snd_dma_free_pages(&chip->work_ptr);
- if (chip->irq >= 0)
- free_irq(chip->irq, chip);
release_and_free_resource(chip->res_reg_area);
pci_write_config_word(chip->pci, 0x40, chip->old_legacy_ctrl);
pci_disable_device(chip->pci);
-#ifndef CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL
release_firmware(chip->dsp_microcode);
release_firmware(chip->controller_microcode);
-#endif
kfree(chip);
return 0;
}
chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
+ snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
snd_ymfpci_disable_dsp(chip);
pci_disable_device(pci);
pci_save_state(pci);
chip->pci = pci;
chip->irq = -1;
chip->device_id = pci->device;
- pci_read_config_byte(pci, PCI_REVISION_ID, &chip->rev);
+ chip->rev = pci->revision;
chip->reg_area_phys = pci_resource_start(pci, 0);
chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000);
pci_set_master(pci);