diff options
-rw-r--r-- | include/linux/usb/audio-v2.h | 12 | ||||
-rw-r--r-- | include/linux/usb/audio.h | 19 | ||||
-rw-r--r-- | sound/usb/mixer.c | 100 |
3 files changed, 115 insertions, 16 deletions
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 0952231e6c3f..2389f93a28b5 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h | |||
@@ -105,6 +105,17 @@ struct uac_as_header_descriptor_v2 { | |||
105 | __u8 iChannelNames; | 105 | __u8 iChannelNames; |
106 | } __attribute__((packed)); | 106 | } __attribute__((packed)); |
107 | 107 | ||
108 | /* 6.1 Interrupt Data Message */ | ||
109 | |||
110 | #define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0) | ||
111 | #define UAC2_INTERRUPT_DATA_MSG_EP (1 << 1) | ||
112 | |||
113 | struct uac2_interrupt_data_msg { | ||
114 | __u8 bInfo; | ||
115 | __u8 bAttribute; | ||
116 | __le16 wValue; | ||
117 | __le16 wIndex; | ||
118 | } __attribute__((packed)); | ||
108 | 119 | ||
109 | /* A.7 Audio Function Category Codes */ | 120 | /* A.7 Audio Function Category Codes */ |
110 | #define UAC2_FUNCTION_SUBCLASS_UNDEFINED 0x00 | 121 | #define UAC2_FUNCTION_SUBCLASS_UNDEFINED 0x00 |
@@ -153,6 +164,7 @@ struct uac_as_header_descriptor_v2 { | |||
153 | /* A.14 Audio Class-Specific Request Codes */ | 164 | /* A.14 Audio Class-Specific Request Codes */ |
154 | #define UAC2_CS_CUR 0x01 | 165 | #define UAC2_CS_CUR 0x01 |
155 | #define UAC2_CS_RANGE 0x02 | 166 | #define UAC2_CS_RANGE 0x02 |
167 | #define UAC2_CS_MEM 0x03 | ||
156 | 168 | ||
157 | /* A.15 Encoder Type Codes */ | 169 | /* A.15 Encoder Type Codes */ |
158 | #define UAC2_ENCODER_UNDEFINED 0x00 | 170 | #define UAC2_ENCODER_UNDEFINED 0x00 |
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index 905a87caf3fb..c0ef18dc2da7 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h | |||
@@ -244,7 +244,7 @@ struct uac_selector_unit_descriptor { | |||
244 | static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) | 244 | static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) |
245 | { | 245 | { |
246 | __u8 *raw = (__u8 *) desc; | 246 | __u8 *raw = (__u8 *) desc; |
247 | return raw[desc->bLength - 1]; | 247 | return raw[9 + desc->bLength - 1]; |
248 | } | 248 | } |
249 | 249 | ||
250 | /* 4.3.2.5 Feature Unit Descriptor */ | 250 | /* 4.3.2.5 Feature Unit Descriptor */ |
@@ -456,7 +456,7 @@ struct uac_iso_endpoint_descriptor { | |||
456 | __u8 bmAttributes; | 456 | __u8 bmAttributes; |
457 | __u8 bLockDelayUnits; | 457 | __u8 bLockDelayUnits; |
458 | __le16 wLockDelay; | 458 | __le16 wLockDelay; |
459 | }; | 459 | } __attribute__((packed)); |
460 | #define UAC_ISO_ENDPOINT_DESC_SIZE 7 | 460 | #define UAC_ISO_ENDPOINT_DESC_SIZE 7 |
461 | 461 | ||
462 | #define UAC_EP_CS_ATTR_SAMPLE_RATE 0x01 | 462 | #define UAC_EP_CS_ATTR_SAMPLE_RATE 0x01 |
@@ -488,6 +488,21 @@ struct uac_iso_endpoint_descriptor { | |||
488 | #define UAC_FU_BASS_BOOST (1 << (UAC_BASS_BOOST_CONTROL - 1)) | 488 | #define UAC_FU_BASS_BOOST (1 << (UAC_BASS_BOOST_CONTROL - 1)) |
489 | #define UAC_FU_LOUDNESS (1 << (UAC_LOUDNESS_CONTROL - 1)) | 489 | #define UAC_FU_LOUDNESS (1 << (UAC_LOUDNESS_CONTROL - 1)) |
490 | 490 | ||
491 | /* status word format (3.7.1.1) */ | ||
492 | |||
493 | #define UAC1_STATUS_TYPE_ORIG_MASK 0x0f | ||
494 | #define UAC1_STATUS_TYPE_ORIG_AUDIO_CONTROL_IF 0x0 | ||
495 | #define UAC1_STATUS_TYPE_ORIG_AUDIO_STREAM_IF 0x1 | ||
496 | #define UAC1_STATUS_TYPE_ORIG_AUDIO_STREAM_EP 0x2 | ||
497 | |||
498 | #define UAC1_STATUS_TYPE_IRQ_PENDING (1 << 7) | ||
499 | #define UAC1_STATUS_TYPE_MEM_CHANGED (1 << 6) | ||
500 | |||
501 | struct uac1_status_word { | ||
502 | __u8 bStatusType; | ||
503 | __u8 bOriginator; | ||
504 | } __attribute__((packed)); | ||
505 | |||
491 | #ifdef __KERNEL__ | 506 | #ifdef __KERNEL__ |
492 | 507 | ||
493 | struct usb_audio_control { | 508 | struct usb_audio_control { |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 21613fe0c1a2..97dd17655104 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -656,7 +656,7 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
656 | case UAC_FEATURE_UNIT: { | 656 | case UAC_FEATURE_UNIT: { |
657 | /* the header is the same for v1 and v2 */ | 657 | /* the header is the same for v1 and v2 */ |
658 | struct uac_feature_unit_descriptor *d = p1; | 658 | struct uac_feature_unit_descriptor *d = p1; |
659 | id = d->bUnitID; | 659 | id = d->bSourceID; |
660 | break; /* continue to parse */ | 660 | break; /* continue to parse */ |
661 | } | 661 | } |
662 | case UAC_MIXER_UNIT: { | 662 | case UAC_MIXER_UNIT: { |
@@ -1443,8 +1443,8 @@ static struct procunit_info procunits[] = { | |||
1443 | * predefined data for extension units | 1443 | * predefined data for extension units |
1444 | */ | 1444 | */ |
1445 | static struct procunit_value_info clock_rate_xu_info[] = { | 1445 | static 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 | }; |
1449 | static struct procunit_value_info clock_source_xu_info[] = { | 1449 | static 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 | ||
1970 | static void snd_usb_mixer_status_complete(struct urb *urb) | 1970 | static 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 | |||
2016 | static 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 | |||
2061 | requeue: | ||
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 | } |