diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2009-10-22 03:06:19 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-11-24 04:19:49 -0500 |
commit | 96f61d9ade82f3e9503df36809175325e8f5eaca (patch) | |
tree | f66c2359f060be40f91dab32a49c2f4320f3edad /sound/usb/usbmidi.c | |
parent | 88cdca9c7376f2220171d09dfc2f9e41b4834435 (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/usbmidi.c')
-rw-r--r-- | sound/usb/usbmidi.c | 107 |
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 | ||
121 | struct snd_usb_midi_out_endpoint { | 126 | struct snd_usb_midi_out_endpoint { |
@@ -879,6 +884,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { | |||
879 | }; | 884 | }; |
880 | 885 | ||
881 | 886 | ||
887 | static 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 | |||
906 | static 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 | |||
882 | static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) | 931 | static 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 | ||
904 | static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) | 954 | static 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 | ||
955 | static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) | 1006 | static 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 | ||
960 | static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) | 1012 | static 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 | ||
1581 | static 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 | |||
1595 | static 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 | |||
1602 | static 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 | |||
1618 | static 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 | ||