aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-05-11 12:13:50 -0400
committerTakashi Iwai <tiwai@suse.de>2010-05-11 16:44:07 -0400
commite213e9cf707c51808e372dabd1070a61af17e77b (patch)
tree320ddb8fce3b554d1555c698c840437250928ca2 /sound/usb
parent0350b6a0cbeaf46e0883d8c79ede2efd49965472 (diff)
ALSA: sound/usb: add preliminary support for UAC2 interrupts
For both UAC1 and UAC2, interrupt endpoint messages are now parsed with structs rather that with anonymous buffer array accesses. For UAC2, only CUR interrupt notifications are supported for now. snd_usb_mixer_status_complete() was renamed to snd_usb_mixer_interrupt(). Fixed one indentation flaw on the way. Signed-off-by: Daniel Mack <daniel@caiaq.de> Cc: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/mixer.c98
1 files changed, 85 insertions, 13 deletions
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index e350f053440a..820dfe08ac22 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1443,8 +1443,8 @@ static struct procunit_info procunits[] = {
1443 * predefined data for extension units 1443 * predefined data for extension units
1444 */ 1444 */
1445static struct procunit_value_info clock_rate_xu_info[] = { 1445static struct procunit_value_info clock_rate_xu_info[] = {
1446 { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, 1446 { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 },
1447 { 0 } 1447 { 0 }
1448}; 1448};
1449static struct procunit_value_info clock_source_xu_info[] = { 1449static struct procunit_value_info clock_source_xu_info[] = {
1450 { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, 1450 { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN },
@@ -1967,26 +1967,98 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
1967 } 1967 }
1968} 1968}
1969 1969
1970static void snd_usb_mixer_status_complete(struct urb *urb) 1970static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
1971 int attribute, int value, int index)
1972{
1973 struct usb_mixer_elem_info *info;
1974 __u8 unitid = (index >> 8) & 0xff;
1975 __u8 control = (value >> 8) & 0xff;
1976 __u8 channel = value & 0xff;
1977
1978 if (channel >= MAX_CHANNELS) {
1979 snd_printk(KERN_DEBUG "%s(): bogus channel number %d\n",
1980 __func__, channel);
1981 return;
1982 }
1983
1984 for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) {
1985 if (info->control != control)
1986 continue;
1987
1988 switch (attribute) {
1989 case UAC2_CS_CUR:
1990 /* invalidate cache, so the value is read from the device */
1991 if (channel)
1992 info->cached &= ~(1 << channel);
1993 else /* master channel */
1994 info->cached = 0;
1995
1996 snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1997 info->elem_id);
1998 break;
1999
2000 case UAC2_CS_RANGE:
2001 /* TODO */
2002 break;
2003
2004 case UAC2_CS_MEM:
2005 /* TODO */
2006 break;
2007
2008 default:
2009 snd_printk(KERN_DEBUG "unknown attribute %d in interrupt\n",
2010 attribute);
2011 break;
2012 } /* switch */
2013 }
2014}
2015
2016static void snd_usb_mixer_interrupt(struct urb *urb)
1971{ 2017{
1972 struct usb_mixer_interface *mixer = urb->context; 2018 struct usb_mixer_interface *mixer = urb->context;
2019 int len = urb->actual_length;
2020
2021 if (urb->status != 0)
2022 goto requeue;
1973 2023
1974 if (urb->status == 0) { 2024 if (mixer->protocol == UAC_VERSION_1) {
1975 u8 *buf = urb->transfer_buffer; 2025 struct uac1_status_word *status;
1976 int i;
1977 2026
1978 for (i = urb->actual_length; i >= 2; buf += 2, i -= 2) { 2027 for (status = urb->transfer_buffer;
2028 len >= sizeof(*status);
2029 len -= sizeof(*status), status++) {
1979 snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n", 2030 snd_printd(KERN_DEBUG "status interrupt: %02x %02x\n",
1980 buf[0], buf[1]); 2031 status->bStatusType,
2032 status->bOriginator);
2033
1981 /* ignore any notifications not from the control interface */ 2034 /* ignore any notifications not from the control interface */
1982 if ((buf[0] & 0x0f) != 0) 2035 if ((status->bStatusType & UAC1_STATUS_TYPE_ORIG_MASK) !=
2036 UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF)
1983 continue; 2037 continue;
1984 if (!(buf[0] & 0x40)) 2038
1985 snd_usb_mixer_notify_id(mixer, buf[1]); 2039 if (status->bStatusType & UAC1_STATUS_TYPE_MEM_CHANGED)
2040 snd_usb_mixer_rc_memory_change(mixer, status->bOriginator);
1986 else 2041 else
1987 snd_usb_mixer_rc_memory_change(mixer, buf[1]); 2042 snd_usb_mixer_notify_id(mixer, status->bOriginator);
2043 }
2044 } else { /* UAC_VERSION_2 */
2045 struct uac2_interrupt_data_msg *msg;
2046
2047 for (msg = urb->transfer_buffer;
2048 len >= sizeof(*msg);
2049 len -= sizeof(*msg), msg++) {
2050 /* drop vendor specific and endpoint requests */
2051 if ((msg->bInfo & UAC2_INTERRUPT_DATA_MSG_VENDOR) ||
2052 (msg->bInfo & UAC2_INTERRUPT_DATA_MSG_EP))
2053 continue;
2054
2055 snd_usb_mixer_interrupt_v2(mixer, msg->bAttribute,
2056 le16_to_cpu(msg->wValue),
2057 le16_to_cpu(msg->wIndex));
1988 } 2058 }
1989 } 2059 }
2060
2061requeue:
1990 if (urb->status != -ENOENT && urb->status != -ECONNRESET) { 2062 if (urb->status != -ENOENT && urb->status != -ECONNRESET) {
1991 urb->dev = mixer->chip->dev; 2063 urb->dev = mixer->chip->dev;
1992 usb_submit_urb(urb, GFP_ATOMIC); 2064 usb_submit_urb(urb, GFP_ATOMIC);
@@ -2023,7 +2095,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
2023 usb_fill_int_urb(mixer->urb, mixer->chip->dev, 2095 usb_fill_int_urb(mixer->urb, mixer->chip->dev,
2024 usb_rcvintpipe(mixer->chip->dev, epnum), 2096 usb_rcvintpipe(mixer->chip->dev, epnum),
2025 transfer_buffer, buffer_length, 2097 transfer_buffer, buffer_length,
2026 snd_usb_mixer_status_complete, mixer, ep->bInterval); 2098 snd_usb_mixer_interrupt, mixer, ep->bInterval);
2027 usb_submit_urb(mixer->urb, GFP_KERNEL); 2099 usb_submit_urb(mixer->urb, GFP_KERNEL);
2028 return 0; 2100 return 0;
2029} 2101}