Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+95 −15
Original line number Diff line number Diff line
@@ -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 
+10 −7
Original line number Diff line number Diff line
@@ -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)