Commit 3a165680 authored by Stuart Brady's avatar Stuart Brady Committed by Kyle McMartin

[PARISC] Update harmony from parisc tree

o Added a control for the input source (which can be either
  "line" or "mic")

o Mute the speaker/line-out/headphone outputs by default.

o Increased the buffer size from 10 pages to 16.
Signed-off-by: default avatarStuart Brady <sdb@parisc-linux.org>

ALSA Harmony was resetting the capture position when
preparing the capture substream, which it shouldn't do.
This should fix the problem.
Signed-off-by: default avatarStuart Brady <sdb@parisc-linux.org>

ALSA Harmony should no longer play junk (left in the buffers
from a previous stream) at the start of a new stream.

Implement the monitor mixer channel for ALSA Harmony.

Also prevent snd_harmony_volume_get from returning negative values.
Signed-off-by: default avatarStuart Brady <sdb@parisc-linux.org>

Use the graveyard/silence buffers in ALSA Harmony.
Signed-off-by: default avatarStuart Brady <sdb@parisc-linux.org>
Signed-off-by: default avatarKyle McMartin <kyle@parisc-linux.org>
parent 5cd55b0e
......@@ -197,7 +197,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
spin_unlock(&h->lock);
if (dstatus & HARMONY_DSTATUS_PN) {
if (h->psubs) {
if (h->psubs && h->st.playing) {
spin_lock(&h->lock);
h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */
......@@ -216,7 +216,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
}
if (dstatus & HARMONY_DSTATUS_RN) {
if (h->csubs) {
if (h->csubs && h->st.capturing) {
spin_lock(&h->lock);
h->cbuf.buf += h->cbuf.count;
h->cbuf.buf %= h->cbuf.size;
......@@ -316,6 +316,7 @@ snd_harmony_playback_trigger(snd_pcm_substream_t *ss, int cmd)
case SNDRV_PCM_TRIGGER_STOP:
h->st.playing = 0;
harmony_mute(h);
harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
harmony_disable_interrupts(h);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
......@@ -352,6 +353,7 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd)
case SNDRV_PCM_TRIGGER_STOP:
h->st.capturing = 0;
harmony_mute(h);
harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
harmony_disable_interrupts(h);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
......@@ -408,6 +410,7 @@ snd_harmony_playback_prepare(snd_pcm_substream_t *ss)
h->pbuf.size = snd_pcm_lib_buffer_bytes(ss);
h->pbuf.count = snd_pcm_lib_period_bytes(ss);
if (h->pbuf.buf >= h->pbuf.size)
h->pbuf.buf = 0;
h->st.playing = 0;
......@@ -437,6 +440,7 @@ snd_harmony_capture_prepare(snd_pcm_substream_t *ss)
h->cbuf.size = snd_pcm_lib_buffer_bytes(ss);
h->cbuf.count = snd_pcm_lib_period_bytes(ss);
if (h->cbuf.buf >= h->cbuf.size)
h->cbuf.buf = 0;
h->st.capturing = 0;
......@@ -712,12 +716,13 @@ snd_harmony_volume_get(snd_kcontrol_t *kc,
left = (h->st.gain >> shift_left) & mask;
right = (h->st.gain >> shift_right) & mask;
if (invert) {
left = mask - left;
right = mask - right;
}
ucontrol->value.integer.value[0] = left;
if (shift_left != shift_right)
ucontrol->value.integer.value[1] = right;
spin_unlock_irqrestore(&h->mixer_lock, flags);
......@@ -738,22 +743,82 @@ snd_harmony_volume_put(snd_kcontrol_t *kc,
int old_gain = h->st.gain;
unsigned long flags;
spin_lock_irqsave(&h->mixer_lock, flags);
left = ucontrol->value.integer.value[0] & mask;
right = ucontrol->value.integer.value[1] & mask;
if (invert) {
if (invert)
left = mask - left;
h->st.gain &= ~( (mask << shift_left ) );
h->st.gain |= (left << shift_left);
if (shift_left != shift_right) {
right = ucontrol->value.integer.value[1] & mask;
if (invert)
right = mask - right;
h->st.gain &= ~( (mask << shift_right) );
h->st.gain |= (right << shift_right);
}
snd_harmony_set_new_gain(h);
spin_unlock_irqrestore(&h->mixer_lock, flags);
return h->st.gain != old_gain;
}
static int
snd_harmony_captureroute_info(snd_kcontrol_t *kc,
snd_ctl_elem_info_t *uinfo)
{
static char *texts[2] = { "Line", "Mic" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 2;
if (uinfo->value.enumerated.item > 1)
uinfo->value.enumerated.item = 1;
strcpy(uinfo->value.enumerated.name,
texts[uinfo->value.enumerated.item]);
return 0;
}
static int
snd_harmony_captureroute_get(snd_kcontrol_t *kc,
snd_ctl_elem_value_t *ucontrol)
{
harmony_t *h = snd_kcontrol_chip(kc);
int value;
unsigned long flags;
spin_lock_irqsave(&h->mixer_lock, flags);
value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1;
ucontrol->value.enumerated.item[0] = value;
spin_unlock_irqrestore(&h->mixer_lock, flags);
return 0;
}
static int
snd_harmony_captureroute_put(snd_kcontrol_t *kc,
snd_ctl_elem_value_t *ucontrol)
{
harmony_t *h = snd_kcontrol_chip(kc);
int value;
int old_gain = h->st.gain;
unsigned long flags;
spin_lock_irqsave(&h->mixer_lock, flags);
h->st.gain &= ~( (mask << shift_right) | (mask << shift_left) );
h->st.gain |= ( (left << shift_left) | (right << shift_right) );
value = ucontrol->value.enumerated.item[0] & 1;
h->st.gain &= ~HARMONY_GAIN_IS_MASK;
h->st.gain |= value << HARMONY_GAIN_IS_SHIFT;
snd_harmony_set_new_gain(h);
spin_unlock_irqrestore(&h->mixer_lock, flags);
return (old_gain - h->st.gain);
return h->st.gain != old_gain;
}
#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/ \
......@@ -767,10 +832,25 @@ snd_harmony_volume_put(snd_kcontrol_t *kc,
((mask) << 16) | ((invert) << 24)) }
static snd_kcontrol_new_t snd_harmony_controls[] = {
HARMONY_VOLUME("Playback Volume", HARMONY_GAIN_LO_SHIFT,
HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT,
HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1),
HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT,
HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0),
HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT,
HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Route",
.info = snd_harmony_captureroute_info,
.get = snd_harmony_captureroute_get,
.put = snd_harmony_captureroute_put
},
HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT,
HARMONY_GAIN_SE_SHIFT, 1, 0),
HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT,
HARMONY_GAIN_LE_SHIFT, 1, 0),
HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT,
HARMONY_GAIN_HE_SHIFT, 1, 0),
};
static void __init
......
......@@ -61,7 +61,7 @@ typedef struct snd_card_harmony {
#define HARMONY_SIZE 64
#define BUF_SIZE PAGE_SIZE
#define MAX_BUFS 10
#define MAX_BUFS 16
#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE)
#define PLAYBACK_BUFS MAX_BUFS
......@@ -101,28 +101,31 @@ typedef struct snd_card_harmony {
#define HARMONY_SS_MONO 0x00000000
#define HARMONY_SS_STEREO 0x00000001
#define HARMONY_GAIN_SILENCE 0x00F00FFF
#define HARMONY_GAIN_DEFAULT 0x0FF00000
#define HARMONY_GAIN_SILENCE 0x01F00FFF
#define HARMONY_GAIN_DEFAULT 0x01F00FFF
#define HARMONY_GAIN_HE_SHIFT 27
#define HARMONY_GAIN_HE_SHIFT 27 /* headphones enabled */
#define HARMONY_GAIN_HE_MASK (1 << HARMONY_GAIN_HE_SHIFT)
#define HARMONY_GAIN_LE_SHIFT 26
#define HARMONY_GAIN_LE_SHIFT 26 /* line-out enabled */
#define HARMONY_GAIN_LE_MASK (1 << HARMONY_GAIN_LE_SHIFT)
#define HARMONY_GAIN_SE_SHIFT 25
#define HARMONY_GAIN_SE_SHIFT 25 /* internal-speaker enabled */
#define HARMONY_GAIN_SE_MASK (1 << HARMONY_GAIN_SE_SHIFT)
#define HARMONY_GAIN_IS_SHIFT 24
#define HARMONY_GAIN_IS_SHIFT 24 /* input select - 0 for line, 1 for mic */
#define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT)
/* monitor attenuation */
#define HARMONY_GAIN_MA 0x0f
#define HARMONY_GAIN_MA_SHIFT 20
#define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT)
/* input gain */
#define HARMONY_GAIN_IN 0x0f
#define HARMONY_GAIN_LI_SHIFT 16
#define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT)
#define HARMONY_GAIN_RI_SHIFT 12
#define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT)
/* output gain (master volume) */
#define HARMONY_GAIN_OUT 0x3f
#define HARMONY_GAIN_LO_SHIFT 6
#define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment