aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2009-10-22 03:06:19 -0400
committerTakashi Iwai <tiwai@suse.de>2009-11-24 04:19:49 -0500
commit96f61d9ade82f3e9503df36809175325e8f5eaca (patch)
treef66c2359f060be40f91dab32a49c2f4320f3edad /sound/usb
parent88cdca9c7376f2220171d09dfc2f9e41b4834435 (diff)
sound: usb-audio: allow switching altsetting on Roland USB MIDI devices
Add a mixer control to select between the two altsettings on Roland USB MIDI devices where the input endpoint is either bulk or interrupt. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/usbmidi.c107
1 files changed, 106 insertions, 1 deletions
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index e5b068996371..80b2845bc486 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * usbmidi.c - ALSA USB MIDI driver 2 * usbmidi.c - ALSA USB MIDI driver
3 * 3 *
4 * Copyright (c) 2002-2007 Clemens Ladisch 4 * Copyright (c) 2002-2009 Clemens Ladisch
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Based on the OSS usb-midi driver by NAGANO Daisuke, 7 * Based on the OSS usb-midi driver by NAGANO Daisuke,
@@ -47,6 +47,7 @@
47#include <linux/usb.h> 47#include <linux/usb.h>
48#include <linux/wait.h> 48#include <linux/wait.h>
49#include <sound/core.h> 49#include <sound/core.h>
50#include <sound/control.h>
50#include <sound/rawmidi.h> 51#include <sound/rawmidi.h>
51#include <sound/asequencer.h> 52#include <sound/asequencer.h>
52#include "usbaudio.h" 53#include "usbaudio.h"
@@ -109,13 +110,17 @@ struct snd_usb_midi {
109 struct list_head list; 110 struct list_head list;
110 struct timer_list error_timer; 111 struct timer_list error_timer;
111 spinlock_t disc_lock; 112 spinlock_t disc_lock;
113 struct mutex mutex;
112 114
113 struct snd_usb_midi_endpoint { 115 struct snd_usb_midi_endpoint {
114 struct snd_usb_midi_out_endpoint *out; 116 struct snd_usb_midi_out_endpoint *out;
115 struct snd_usb_midi_in_endpoint *in; 117 struct snd_usb_midi_in_endpoint *in;
116 } endpoints[MIDI_MAX_ENDPOINTS]; 118 } endpoints[MIDI_MAX_ENDPOINTS];
117 unsigned long input_triggered; 119 unsigned long input_triggered;
120 unsigned int opened;
118 unsigned char disconnected; 121 unsigned char disconnected;
122
123 struct snd_kcontrol *roland_load_ctl;
119}; 124};
120 125
121struct snd_usb_midi_out_endpoint { 126struct snd_usb_midi_out_endpoint {
@@ -879,6 +884,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = {
879}; 884};
880 885
881 886
887static void update_roland_altsetting(struct snd_usb_midi* umidi)
888{
889 struct usb_interface *intf;
890 struct usb_host_interface *hostif;
891 struct usb_interface_descriptor *intfd;
892 int is_light_load;
893
894 intf = umidi->iface;
895 is_light_load = intf->cur_altsetting != intf->altsetting;
896 if (umidi->roland_load_ctl->private_value == is_light_load)
897 return;
898 hostif = &intf->altsetting[umidi->roland_load_ctl->private_value];
899 intfd = get_iface_desc(hostif);
900 snd_usbmidi_input_stop(&umidi->list);
901 usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
902 intfd->bAlternateSetting);
903 snd_usbmidi_input_start(&umidi->list);
904}
905
906static void substream_open(struct snd_rawmidi_substream *substream, int open)
907{
908 struct snd_usb_midi* umidi = substream->rmidi->private_data;
909 struct snd_kcontrol *ctl;
910
911 mutex_lock(&umidi->mutex);
912 if (open) {
913 if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
914 ctl = umidi->roland_load_ctl;
915 ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
916 snd_ctl_notify(umidi->chip->card,
917 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
918 update_roland_altsetting(umidi);
919 }
920 } else {
921 if (--umidi->opened == 0 && umidi->roland_load_ctl) {
922 ctl = umidi->roland_load_ctl;
923 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
924 snd_ctl_notify(umidi->chip->card,
925 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
926 }
927 }
928 mutex_unlock(&umidi->mutex);
929}
930
882static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) 931static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
883{ 932{
884 struct snd_usb_midi* umidi = substream->rmidi->private_data; 933 struct snd_usb_midi* umidi = substream->rmidi->private_data;
@@ -898,11 +947,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
898 } 947 }
899 substream->runtime->private_data = port; 948 substream->runtime->private_data = port;
900 port->state = STATE_UNKNOWN; 949 port->state = STATE_UNKNOWN;
950 substream_open(substream, 1);
901 return 0; 951 return 0;
902} 952}
903 953
904static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) 954static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
905{ 955{
956 substream_open(substream, 0);
906 return 0; 957 return 0;
907} 958}
908 959
@@ -954,11 +1005,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
954 1005
955static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) 1006static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
956{ 1007{
1008 substream_open(substream, 1);
957 return 0; 1009 return 0;
958} 1010}
959 1011
960static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) 1012static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
961{ 1013{
1014 substream_open(substream, 0);
962 return 0; 1015 return 0;
963} 1016}
964 1017
@@ -1163,6 +1216,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi)
1163 if (ep->in) 1216 if (ep->in)
1164 snd_usbmidi_in_endpoint_delete(ep->in); 1217 snd_usbmidi_in_endpoint_delete(ep->in);
1165 } 1218 }
1219 mutex_destroy(&umidi->mutex);
1166 kfree(umidi); 1220 kfree(umidi);
1167} 1221}
1168 1222
@@ -1524,6 +1578,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi,
1524 return 0; 1578 return 0;
1525} 1579}
1526 1580
1581static int roland_load_info(struct snd_kcontrol *kcontrol,
1582 struct snd_ctl_elem_info *info)
1583{
1584 static const char *const names[] = { "High Load", "Light Load" };
1585
1586 info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1587 info->count = 1;
1588 info->value.enumerated.items = 2;
1589 if (info->value.enumerated.item > 1)
1590 info->value.enumerated.item = 1;
1591 strcpy(info->value.enumerated.name, names[info->value.enumerated.item]);
1592 return 0;
1593}
1594
1595static int roland_load_get(struct snd_kcontrol *kcontrol,
1596 struct snd_ctl_elem_value *value)
1597{
1598 value->value.enumerated.item[0] = kcontrol->private_value;
1599 return 0;
1600}
1601
1602static int roland_load_put(struct snd_kcontrol *kcontrol,
1603 struct snd_ctl_elem_value *value)
1604{
1605 struct snd_usb_midi* umidi = kcontrol->private_data;
1606 int changed;
1607
1608 if (value->value.enumerated.item[0] > 1)
1609 return -EINVAL;
1610 mutex_lock(&umidi->mutex);
1611 changed = value->value.enumerated.item[0] != kcontrol->private_value;
1612 if (changed)
1613 kcontrol->private_value = value->value.enumerated.item[0];
1614 mutex_unlock(&umidi->mutex);
1615 return changed;
1616}
1617
1618static struct snd_kcontrol_new roland_load_ctl = {
1619 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1620 .name = "MIDI Input Mode",
1621 .info = roland_load_info,
1622 .get = roland_load_get,
1623 .put = roland_load_put,
1624 .private_value = 1,
1625};
1626
1527/* 1627/*
1528 * On Roland devices, use the second alternate setting to be able to use 1628 * On Roland devices, use the second alternate setting to be able to use
1529 * the interrupt input endpoint. 1629 * the interrupt input endpoint.
@@ -1549,6 +1649,10 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi)
1549 intfd->bAlternateSetting); 1649 intfd->bAlternateSetting);
1550 usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, 1650 usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
1551 intfd->bAlternateSetting); 1651 intfd->bAlternateSetting);
1652
1653 umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi);
1654 if (snd_ctl_add(umidi->chip->card, umidi->roland_load_ctl) < 0)
1655 umidi->roland_load_ctl = NULL;
1552} 1656}
1553 1657
1554/* 1658/*
@@ -1834,6 +1938,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip,
1834 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; 1938 umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
1835 init_timer(&umidi->error_timer); 1939 init_timer(&umidi->error_timer);
1836 spin_lock_init(&umidi->disc_lock); 1940 spin_lock_init(&umidi->disc_lock);
1941 mutex_init(&umidi->mutex);
1837 umidi->error_timer.function = snd_usbmidi_error_timer; 1942 umidi->error_timer.function = snd_usbmidi_error_timer;
1838 umidi->error_timer.data = (unsigned long)umidi; 1943 umidi->error_timer.data = (unsigned long)umidi;
1839 1944