[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: Stuart 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: Stuart 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: Stuart Brady <sdb@parisc-linux.org> Use the graveyard/silence buffers in ALSA Harmony. Signed-off-by: Stuart Brady <sdb@parisc-linux.org> Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
This commit is contained in:
parent
5cd55b0ede
commit
3a16568016
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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:
|
||||||
|
@ -351,8 +352,9 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd)
|
||||||
break;
|
break;
|
||||||
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_disable_interrupts(h);
|
harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
|
||||||
|
harmony_disable_interrupts(h);
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
|
@ -408,7 +410,8 @@ 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);
|
||||||
h->pbuf.buf = 0;
|
if (h->pbuf.buf >= h->pbuf.size)
|
||||||
|
h->pbuf.buf = 0;
|
||||||
h->st.playing = 0;
|
h->st.playing = 0;
|
||||||
|
|
||||||
h->st.rate = snd_harmony_rate_bits(rt->rate);
|
h->st.rate = snd_harmony_rate_bits(rt->rate);
|
||||||
|
@ -437,7 +440,8 @@ 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);
|
||||||
h->cbuf.buf = 0;
|
if (h->cbuf.buf >= h->cbuf.size)
|
||||||
|
h->cbuf.buf = 0;
|
||||||
h->st.capturing = 0;
|
h->st.capturing = 0;
|
||||||
|
|
||||||
h->st.rate = snd_harmony_rate_bits(rt->rate);
|
h->st.rate = snd_harmony_rate_bits(rt->rate);
|
||||||
|
@ -712,13 +716,14 @@ 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;
|
||||||
ucontrol->value.integer.value[1] = right;
|
if (shift_left != shift_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,
|
||||||
int old_gain = h->st.gain;
|
int old_gain = h->st.gain;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
left = ucontrol->value.integer.value[0] & mask;
|
|
||||||
right = ucontrol->value.integer.value[1] & mask;
|
|
||||||
if (invert) {
|
|
||||||
left = mask - left;
|
|
||||||
right = mask - right;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_irqsave(&h->mixer_lock, flags);
|
spin_lock_irqsave(&h->mixer_lock, flags);
|
||||||
|
|
||||||
h->st.gain &= ~( (mask << shift_right) | (mask << shift_left) );
|
left = ucontrol->value.integer.value[0] & mask;
|
||||||
h->st.gain |= ( (left << shift_left) | (right << shift_right) );
|
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);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 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,
|
||||||
((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 {
|
||||||
#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 {
|
||||||
#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)
|
||||||
|
|
Loading…
Reference in New Issue