aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/parisc/harmony.c110
-rw-r--r--sound/parisc/harmony.h17
2 files changed, 105 insertions, 22 deletions
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 8b3ea26469ad..d833349ed518 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -197,7 +197,7 @@ snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
197 spin_unlock(&h->lock); 197 spin_unlock(&h->lock);
198 198
199 if (dstatus & HARMONY_DSTATUS_PN) { 199 if (dstatus & HARMONY_DSTATUS_PN) {
200 if (h->psubs) { 200 if (h->psubs && h->st.playing) {
201 spin_lock(&h->lock); 201 spin_lock(&h->lock);
202 h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */ 202 h->pbuf.buf += h->pbuf.count; /* PAGE_SIZE */
203 h->pbuf.buf %= h->pbuf.size; /* MAX_BUFS*PAGE_SIZE */ 203 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 } 216 }
217 217
218 if (dstatus & HARMONY_DSTATUS_RN) { 218 if (dstatus & HARMONY_DSTATUS_RN) {
219 if (h->csubs) { 219 if (h->csubs && h->st.capturing) {
220 spin_lock(&h->lock); 220 spin_lock(&h->lock);
221 h->cbuf.buf += h->cbuf.count; 221 h->cbuf.buf += h->cbuf.count;
222 h->cbuf.buf %= h->cbuf.size; 222 h->cbuf.buf %= h->cbuf.size;
@@ -316,6 +316,7 @@ snd_harmony_playback_trigger(snd_pcm_substream_t *ss, int cmd)
316 case SNDRV_PCM_TRIGGER_STOP: 316 case SNDRV_PCM_TRIGGER_STOP:
317 h->st.playing = 0; 317 h->st.playing = 0;
318 harmony_mute(h); 318 harmony_mute(h);
319 harmony_write(h, HARMONY_PNXTADD, h->sdma.addr);
319 harmony_disable_interrupts(h); 320 harmony_disable_interrupts(h);
320 break; 321 break;
321 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 322 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -351,8 +352,9 @@ snd_harmony_capture_trigger(snd_pcm_substream_t *ss, int cmd)
351 break; 352 break;
352 case SNDRV_PCM_TRIGGER_STOP: 353 case SNDRV_PCM_TRIGGER_STOP:
353 h->st.capturing = 0; 354 h->st.capturing = 0;
354 harmony_mute(h); 355 harmony_mute(h);
355 harmony_disable_interrupts(h); 356 harmony_write(h, HARMONY_RNXTADD, h->gdma.addr);
357 harmony_disable_interrupts(h);
356 break; 358 break;
357 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 359 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
358 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 360 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -408,7 +410,8 @@ snd_harmony_playback_prepare(snd_pcm_substream_t *ss)
408 410
409 h->pbuf.size = snd_pcm_lib_buffer_bytes(ss); 411 h->pbuf.size = snd_pcm_lib_buffer_bytes(ss);
410 h->pbuf.count = snd_pcm_lib_period_bytes(ss); 412 h->pbuf.count = snd_pcm_lib_period_bytes(ss);
411 h->pbuf.buf = 0; 413 if (h->pbuf.buf >= h->pbuf.size)
414 h->pbuf.buf = 0;
412 h->st.playing = 0; 415 h->st.playing = 0;
413 416
414 h->st.rate = snd_harmony_rate_bits(rt->rate); 417 h->st.rate = snd_harmony_rate_bits(rt->rate);
@@ -437,7 +440,8 @@ snd_harmony_capture_prepare(snd_pcm_substream_t *ss)
437 440
438 h->cbuf.size = snd_pcm_lib_buffer_bytes(ss); 441 h->cbuf.size = snd_pcm_lib_buffer_bytes(ss);
439 h->cbuf.count = snd_pcm_lib_period_bytes(ss); 442 h->cbuf.count = snd_pcm_lib_period_bytes(ss);
440 h->cbuf.buf = 0; 443 if (h->cbuf.buf >= h->cbuf.size)
444 h->cbuf.buf = 0;
441 h->st.capturing = 0; 445 h->st.capturing = 0;
442 446
443 h->st.rate = snd_harmony_rate_bits(rt->rate); 447 h->st.rate = snd_harmony_rate_bits(rt->rate);
@@ -712,13 +716,14 @@ snd_harmony_volume_get(snd_kcontrol_t *kc,
712 716
713 left = (h->st.gain >> shift_left) & mask; 717 left = (h->st.gain >> shift_left) & mask;
714 right = (h->st.gain >> shift_right) & mask; 718 right = (h->st.gain >> shift_right) & mask;
715
716 if (invert) { 719 if (invert) {
717 left = mask - left; 720 left = mask - left;
718 right = mask - right; 721 right = mask - right;
719 } 722 }
723
720 ucontrol->value.integer.value[0] = left; 724 ucontrol->value.integer.value[0] = left;
721 ucontrol->value.integer.value[1] = right; 725 if (shift_left != shift_right)
726 ucontrol->value.integer.value[1] = right;
722 727
723 spin_unlock_irqrestore(&h->mixer_lock, flags); 728 spin_unlock_irqrestore(&h->mixer_lock, flags);
724 729
@@ -738,22 +743,82 @@ snd_harmony_volume_put(snd_kcontrol_t *kc,
738 int old_gain = h->st.gain; 743 int old_gain = h->st.gain;
739 unsigned long flags; 744 unsigned long flags;
740 745
746 spin_lock_irqsave(&h->mixer_lock, flags);
747
741 left = ucontrol->value.integer.value[0] & mask; 748 left = ucontrol->value.integer.value[0] & mask;
742 right = ucontrol->value.integer.value[1] & mask; 749 if (invert)
743 if (invert) {
744 left = mask - left; 750 left = mask - left;
745 right = mask - right; 751 h->st.gain &= ~( (mask << shift_left ) );
752 h->st.gain |= (left << shift_left);
753
754 if (shift_left != shift_right) {
755 right = ucontrol->value.integer.value[1] & mask;
756 if (invert)
757 right = mask - right;
758 h->st.gain &= ~( (mask << shift_right) );
759 h->st.gain |= (right << shift_right);
746 } 760 }
761
762 snd_harmony_set_new_gain(h);
763
764 spin_unlock_irqrestore(&h->mixer_lock, flags);
765
766 return h->st.gain != old_gain;
767}
768
769static int
770snd_harmony_captureroute_info(snd_kcontrol_t *kc,
771 snd_ctl_elem_info_t *uinfo)
772{
773 static char *texts[2] = { "Line", "Mic" };
774 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
775 uinfo->count = 1;
776 uinfo->value.enumerated.items = 2;
777 if (uinfo->value.enumerated.item > 1)
778 uinfo->value.enumerated.item = 1;
779 strcpy(uinfo->value.enumerated.name,
780 texts[uinfo->value.enumerated.item]);
781 return 0;
782}
783
784static int
785snd_harmony_captureroute_get(snd_kcontrol_t *kc,
786 snd_ctl_elem_value_t *ucontrol)
787{
788 harmony_t *h = snd_kcontrol_chip(kc);
789 int value;
790 unsigned long flags;
791
792 spin_lock_irqsave(&h->mixer_lock, flags);
793
794 value = (h->st.gain >> HARMONY_GAIN_IS_SHIFT) & 1;
795 ucontrol->value.enumerated.item[0] = value;
796
797 spin_unlock_irqrestore(&h->mixer_lock, flags);
798
799 return 0;
800}
801
802static int
803snd_harmony_captureroute_put(snd_kcontrol_t *kc,
804 snd_ctl_elem_value_t *ucontrol)
805{
806 harmony_t *h = snd_kcontrol_chip(kc);
807 int value;
808 int old_gain = h->st.gain;
809 unsigned long flags;
747 810
748 spin_lock_irqsave(&h->mixer_lock, flags); 811 spin_lock_irqsave(&h->mixer_lock, flags);
749 812
750 h->st.gain &= ~( (mask << shift_right) | (mask << shift_left) ); 813 value = ucontrol->value.enumerated.item[0] & 1;
751 h->st.gain |= ( (left << shift_left) | (right << shift_right) ); 814 h->st.gain &= ~HARMONY_GAIN_IS_MASK;
815 h->st.gain |= value << HARMONY_GAIN_IS_SHIFT;
816
752 snd_harmony_set_new_gain(h); 817 snd_harmony_set_new_gain(h);
753 818
754 spin_unlock_irqrestore(&h->mixer_lock, flags); 819 spin_unlock_irqrestore(&h->mixer_lock, flags);
755 820
756 return (old_gain - h->st.gain); 821 return h->st.gain != old_gain;
757} 822}
758 823
759#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/ \ 824#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/ \
@@ -767,10 +832,25 @@ snd_harmony_volume_put(snd_kcontrol_t *kc,
767 ((mask) << 16) | ((invert) << 24)) } 832 ((mask) << 16) | ((invert) << 24)) }
768 833
769static snd_kcontrol_new_t snd_harmony_controls[] = { 834static snd_kcontrol_new_t snd_harmony_controls[] = {
770 HARMONY_VOLUME("Playback Volume", HARMONY_GAIN_LO_SHIFT, 835 HARMONY_VOLUME("Master Playback Volume", HARMONY_GAIN_LO_SHIFT,
771 HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1), 836 HARMONY_GAIN_RO_SHIFT, HARMONY_GAIN_OUT, 1),
772 HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT, 837 HARMONY_VOLUME("Capture Volume", HARMONY_GAIN_LI_SHIFT,
773 HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0), 838 HARMONY_GAIN_RI_SHIFT, HARMONY_GAIN_IN, 0),
839 HARMONY_VOLUME("Monitor Volume", HARMONY_GAIN_MA_SHIFT,
840 HARMONY_GAIN_MA_SHIFT, HARMONY_GAIN_MA, 1),
841 {
842 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
843 .name = "Input Route",
844 .info = snd_harmony_captureroute_info,
845 .get = snd_harmony_captureroute_get,
846 .put = snd_harmony_captureroute_put
847 },
848 HARMONY_VOLUME("Internal Speaker Switch", HARMONY_GAIN_SE_SHIFT,
849 HARMONY_GAIN_SE_SHIFT, 1, 0),
850 HARMONY_VOLUME("Line-Out Switch", HARMONY_GAIN_LE_SHIFT,
851 HARMONY_GAIN_LE_SHIFT, 1, 0),
852 HARMONY_VOLUME("Headphones Switch", HARMONY_GAIN_HE_SHIFT,
853 HARMONY_GAIN_HE_SHIFT, 1, 0),
774}; 854};
775 855
776static void __init 856static void __init
diff --git a/sound/parisc/harmony.h b/sound/parisc/harmony.h
index ef77f9a577d5..526c52389de2 100644
--- a/sound/parisc/harmony.h
+++ b/sound/parisc/harmony.h
@@ -61,7 +61,7 @@ typedef struct snd_card_harmony {
61#define HARMONY_SIZE 64 61#define HARMONY_SIZE 64
62 62
63#define BUF_SIZE PAGE_SIZE 63#define BUF_SIZE PAGE_SIZE
64#define MAX_BUFS 10 64#define MAX_BUFS 16
65#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE) 65#define MAX_BUF_SIZE (MAX_BUFS * BUF_SIZE)
66 66
67#define PLAYBACK_BUFS MAX_BUFS 67#define PLAYBACK_BUFS MAX_BUFS
@@ -101,28 +101,31 @@ typedef struct snd_card_harmony {
101#define HARMONY_SS_MONO 0x00000000 101#define HARMONY_SS_MONO 0x00000000
102#define HARMONY_SS_STEREO 0x00000001 102#define HARMONY_SS_STEREO 0x00000001
103 103
104#define HARMONY_GAIN_SILENCE 0x00F00FFF 104#define HARMONY_GAIN_SILENCE 0x01F00FFF
105#define HARMONY_GAIN_DEFAULT 0x0FF00000 105#define HARMONY_GAIN_DEFAULT 0x01F00FFF
106 106
107#define HARMONY_GAIN_HE_SHIFT 27 107#define HARMONY_GAIN_HE_SHIFT 27 /* headphones enabled */
108#define HARMONY_GAIN_HE_MASK (1 << HARMONY_GAIN_HE_SHIFT) 108#define HARMONY_GAIN_HE_MASK (1 << HARMONY_GAIN_HE_SHIFT)
109#define HARMONY_GAIN_LE_SHIFT 26 109#define HARMONY_GAIN_LE_SHIFT 26 /* line-out enabled */
110#define HARMONY_GAIN_LE_MASK (1 << HARMONY_GAIN_LE_SHIFT) 110#define HARMONY_GAIN_LE_MASK (1 << HARMONY_GAIN_LE_SHIFT)
111#define HARMONY_GAIN_SE_SHIFT 25 111#define HARMONY_GAIN_SE_SHIFT 25 /* internal-speaker enabled */
112#define HARMONY_GAIN_SE_MASK (1 << HARMONY_GAIN_SE_SHIFT) 112#define HARMONY_GAIN_SE_MASK (1 << HARMONY_GAIN_SE_SHIFT)
113#define HARMONY_GAIN_IS_SHIFT 24 113#define HARMONY_GAIN_IS_SHIFT 24 /* input select - 0 for line, 1 for mic */
114#define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT) 114#define HARMONY_GAIN_IS_MASK (1 << HARMONY_GAIN_IS_SHIFT)
115 115
116/* monitor attenuation */
116#define HARMONY_GAIN_MA 0x0f 117#define HARMONY_GAIN_MA 0x0f
117#define HARMONY_GAIN_MA_SHIFT 20 118#define HARMONY_GAIN_MA_SHIFT 20
118#define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT) 119#define HARMONY_GAIN_MA_MASK (HARMONY_GAIN_MA << HARMONY_GAIN_MA_SHIFT)
119 120
121/* input gain */
120#define HARMONY_GAIN_IN 0x0f 122#define HARMONY_GAIN_IN 0x0f
121#define HARMONY_GAIN_LI_SHIFT 16 123#define HARMONY_GAIN_LI_SHIFT 16
122#define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT) 124#define HARMONY_GAIN_LI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_LI_SHIFT)
123#define HARMONY_GAIN_RI_SHIFT 12 125#define HARMONY_GAIN_RI_SHIFT 12
124#define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT) 126#define HARMONY_GAIN_RI_MASK (HARMONY_GAIN_IN << HARMONY_GAIN_RI_SHIFT)
125 127
128/* output gain (master volume) */
126#define HARMONY_GAIN_OUT 0x3f 129#define HARMONY_GAIN_OUT 0x3f
127#define HARMONY_GAIN_LO_SHIFT 6 130#define HARMONY_GAIN_LO_SHIFT 6
128#define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT) 131#define HARMONY_GAIN_LO_MASK (HARMONY_GAIN_OUT << HARMONY_GAIN_LO_SHIFT)