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) ...@@ -197,7 +197,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
spin_unlock(&h->lock); spin_unlock(&h->lock);
if (dstatus & HARMONY_DSTATUS_PN) { if (dstatus & HARMONY_DSTATUS_PN) {
if (h->psubs) { if (h->psubs && h->st.playing) {
spin_lock(&h->lock); spin_lock(&h->lock);
h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*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) ...@@ -216,7 +216,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
} }
if (dstatus & HARMONY_DSTATUS_RN) { if (dstatus & HARMONY_DSTATUS_RN) {
if (h->csubs) { if (h->csubs && h->st.capturing) {
spin_lock(&h->lock); spin_lock(&h->lock);
h->cbuf.buf += h->cbuf.count; h->cbuf.buf += h->cbuf.count;
h->cbuf.buf %= h->cbuf.size; h->cbuf.buf %= h->cbuf.size;
...@@ -316,6 +316,7 @@ snd_harmony_playback_trigger(snd_pcm_substream_t *ss, int cmd) ...@@ -316,6 +316,7 @@ snd_harmony_playback_trigger(snd_pcm_substream_t *ss, int cmd)
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
h->st.playing = 0; h->st.playing = 0;
harmony_mute(h); harmony_mute(h);
harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
harmony_disable_interrupts(h); harmony_disable_interrupts(h);
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
...@@ -352,6 +353,7 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd) ...@@ -352,6 +353,7 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd)
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
h->st.capturing = 0; h->st.capturing = 0;
harmony_mute(h); harmony_mute(h);
harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
harmony_disable_interrupts(h); harmony_disable_interrupts(h);
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
...@@ -408,6 +410,7 @@ snd_harmony_playback_prepare(snd_pcm_substream_t *ss) ...@@ -408,6 +410,7 @@ snd_harmony_playback_prepare(snd_pcm_substream_t *ss)
h->pbuf.size = snd_pcm_lib_buffer_bytes(ss); h->pbuf.size = snd_pcm_lib_buffer_bytes(ss);
h->pbuf.count = snd_pcm_lib_period_bytes(ss); h->pbuf.count = snd_pcm_lib_period_bytes(ss);
if (h->pbuf.buf >= h->pbuf.size)
h->pbuf.buf = 0; h->pbuf.buf = 0;
h->st.playing = 0; h->st.playing = 0;
...@@ -437,6 +440,7 @@ snd_harmony_capture_prepare(snd_pcm_substream_t *ss) ...@@ -437,6 +440,7 @@ snd_harmony_capture_prepare(snd_pcm_substream_t *ss)
h->cbuf.size = snd_pcm_lib_buffer_bytes(ss); h->cbuf.size = snd_pcm_lib_buffer_bytes(ss);
h->cbuf.count = snd_pcm_lib_period_bytes(ss); h->cbuf.count = snd_pcm_lib_period_bytes(ss);
if (h->cbuf.buf >= h->cbuf.size)
h->cbuf.buf = 0; h->cbuf.buf = 0;
h->st.capturing = 0; h->st.capturing = 0;
...@@ -712,12 +716,13 @@ snd_harmony_volume_get(snd_kcontrol_t *kc, ...@@ -712,12 +716,13 @@ snd_harmony_volume_get(snd_kcontrol_t *kc,
left = (h->st.gain >> shift_left) & mask; left = (h->st.gain >> shift_left) & mask;
right = (h->st.gain >> shift_right) & mask; right = (h->st.gain >> shift_right) & mask;
if (invert) { if (invert) {
left = mask - left; left = mask - left;
right = mask - right; right = mask - right;
} }
ucontrol->value.integer.value[0] = left; ucontrol->value.integer.value[0] = left;
if (shift_left != shift_right)
ucontrol->value.integer.value[1] = right; ucontrol->value.integer.value[1] = right;
spin_unlock_irqrestore(&h->mixer_lock, flags); spin_unlock_irqrestore(&h->mixer_lock, flags);
...@@ -738,22 +743,82 @@ snd_harmony_volume_put(snd_kcontrol_t *kc, ...@@ -738,22 +743,82 @@ snd_harmony_volume_put(snd_kcontrol_t *kc,
int old_gain = h->st.gain; int old_gain = h->st.gain;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&h->mixer_lock, flags);
left = ucontrol->value.integer.value[0] & mask; left = ucontrol->value.integer.value[0] & mask;
right = ucontrol->value.integer.value[1] & mask; if (invert)
if (invert) {
left = mask - left; 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; 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); spin_lock_irqsave(&h->mixer_lock, flags);
h->st.gain &= ~( (mask << shift_right) | (mask << shift_left) ); value = ucontrol->value.enumerated.item[0] & 1;
h->st.gain |= ( (left << shift_left) | (right << shift_right) ); h->st.gain &= ~HARMONY_GAIN_IS_MASK;
h->st.gain |= value << HARMONY_GAIN_IS_SHIFT;
snd_harmony_set_new_gain(h); snd_harmony_set_new_gain(h);
spin_unlock_irqrestore(&h->mixer_lock, flags); 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)/ \ #define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/ \
...@@ -767,10 +832,25 @@ snd_harmony_volume_put(snd_kcontrol_t *kc, ...@@ -767,10 +832,25 @@ snd_harmony_volume_put(snd_kcontrol_t *kc,
((mask) << 16) | ((invert) << 24)) } ((mask) << 16) | ((invert) << 24)) }
static snd_kcontrol_new_t snd_harmony_controls[] = { 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_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1),
HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT, HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT,
HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0), 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 static void __init
......
...@@ -61,7 +61,7 @@ typedef struct snd_card_harmony { ...@@ -61,7 +61,7 @@ typedef struct snd_card_harmony {
#define HARMONY_SIZE 64 #define HARMONY_SIZE 64
#define BUF_SIZE PAGE_SIZE #define BUF_SIZE PAGE_SIZE
#define MAX_BUFS 10 #define MAX_BUFS 16
#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE) #define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE)
#define PLAYBACK_BUFS MAX_BUFS #define PLAYBACK_BUFS MAX_BUFS
...@@ -101,28 +101,31 @@ typedef struct snd_card_harmony { ...@@ -101,28 +101,31 @@ typedef struct snd_card_harmony {
#define HARMONY_SS_MONO 0x00000000 #define HARMONY_SS_MONO 0x00000000
#define HARMONY_SS_STEREO 0x00000001 #define HARMONY_SS_STEREO 0x00000001
#define HARMONY_GAIN_SILENCE 0x00F00FFF #define HARMONY_GAIN_SILENCE 0x01F00FFF
#define HARMONY_GAIN_DEFAULT 0x0FF00000 #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_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_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_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) #define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT)
/* monitor attenuation */
#define HARMONY_GAIN_MA 0x0f #define HARMONY_GAIN_MA 0x0f
#define HARMONY_GAIN_MA_SHIFT 20 #define HARMONY_GAIN_MA_SHIFT 20
#define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT) #define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT)
/* input gain */
#define HARMONY_GAIN_IN 0x0f #define HARMONY_GAIN_IN 0x0f
#define HARMONY_GAIN_LI_SHIFT 16 #define HARMONY_GAIN_LI_SHIFT 16
#define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT) #define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT)
#define HARMONY_GAIN_RI_SHIFT 12 #define HARMONY_GAIN_RI_SHIFT 12
#define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT) #define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT)
/* output gain (master volume) */
#define HARMONY_GAIN_OUT 0x3f #define HARMONY_GAIN_OUT 0x3f
#define HARMONY_GAIN_LO_SHIFT 6 #define HARMONY_GAIN_LO_SHIFT 6
#define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT) #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