aboutsummaryrefslogtreecommitdiffstats
path: root/sound/parisc/harmony.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/parisc/harmony.c')
-rw-r--r--sound/parisc/harmony.c110
1 files changed, 95 insertions, 15 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