diff options
author | Daniel Mack <daniel@caiaq.de> | 2010-02-22 17:49:09 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-02-23 02:40:12 -0500 |
commit | 28e1b773083d349d5223f586a39fa30f5d0f1c36 (patch) | |
tree | 4793eb1d87a094cf3642600ac3b201f81bab7e54 /sound/usb/usbmixer.c | |
parent | 40717382e0c1f572553e4fdefb489db4b95a5e7e (diff) |
ALSA: usbaudio: parse USB descriptors with structs
In preparation of support for v2.0 audio class, use the structs from
linux/usb/audio.h and add some new ones to describe the fields that are
actually parsed by the descriptor decoders.
Also, factor out code from usb_create_streams(). This makes it easier to
adopt the new iteration logic needed for v2.0.
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/usbmixer.c')
-rw-r--r-- | sound/usb/usbmixer.c | 37 |
1 files changed, 20 insertions, 17 deletions
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 35b4830fb0c4..11636a6112d5 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/usb.h> | 34 | #include <linux/usb.h> |
35 | #include <linux/usb/audio.h> | ||
36 | |||
35 | #include <sound/core.h> | 37 | #include <sound/core.h> |
36 | #include <sound/control.h> | 38 | #include <sound/control.h> |
37 | #include <sound/hwdep.h> | 39 | #include <sound/hwdep.h> |
@@ -1086,29 +1088,30 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
1086 | * | 1088 | * |
1087 | * most of controlls are defined here. | 1089 | * most of controlls are defined here. |
1088 | */ | 1090 | */ |
1089 | static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsigned char *ftr) | 1091 | static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr) |
1090 | { | 1092 | { |
1091 | int channels, i, j; | 1093 | int channels, i, j; |
1092 | struct usb_audio_term iterm; | 1094 | struct usb_audio_term iterm; |
1093 | unsigned int master_bits, first_ch_bits; | 1095 | unsigned int master_bits, first_ch_bits; |
1094 | int err, csize; | 1096 | int err, csize; |
1097 | struct uac_feature_unit_descriptor *ftr = _ftr; | ||
1095 | 1098 | ||
1096 | if (ftr[0] < 7 || ! (csize = ftr[5]) || ftr[0] < 7 + csize) { | 1099 | if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) { |
1097 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid); | 1100 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid); |
1098 | return -EINVAL; | 1101 | return -EINVAL; |
1099 | } | 1102 | } |
1100 | 1103 | ||
1101 | /* parse the source unit */ | 1104 | /* parse the source unit */ |
1102 | if ((err = parse_audio_unit(state, ftr[4])) < 0) | 1105 | if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0) |
1103 | return err; | 1106 | return err; |
1104 | 1107 | ||
1105 | /* determine the input source type and name */ | 1108 | /* determine the input source type and name */ |
1106 | if (check_input_term(state, ftr[4], &iterm) < 0) | 1109 | if (check_input_term(state, ftr->bSourceID, &iterm) < 0) |
1107 | return -EINVAL; | 1110 | return -EINVAL; |
1108 | 1111 | ||
1109 | channels = (ftr[0] - 7) / csize - 1; | 1112 | channels = (ftr->bLength - 7) / csize - 1; |
1110 | 1113 | ||
1111 | master_bits = snd_usb_combine_bytes(ftr + 6, csize); | 1114 | master_bits = snd_usb_combine_bytes(ftr->controls, csize); |
1112 | /* master configuration quirks */ | 1115 | /* master configuration quirks */ |
1113 | switch (state->chip->usb_id) { | 1116 | switch (state->chip->usb_id) { |
1114 | case USB_ID(0x08bb, 0x2702): | 1117 | case USB_ID(0x08bb, 0x2702): |
@@ -1119,21 +1122,21 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig | |||
1119 | break; | 1122 | break; |
1120 | } | 1123 | } |
1121 | if (channels > 0) | 1124 | if (channels > 0) |
1122 | first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); | 1125 | first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize); |
1123 | else | 1126 | else |
1124 | first_ch_bits = 0; | 1127 | first_ch_bits = 0; |
1125 | /* check all control types */ | 1128 | /* check all control types */ |
1126 | for (i = 0; i < 10; i++) { | 1129 | for (i = 0; i < 10; i++) { |
1127 | unsigned int ch_bits = 0; | 1130 | unsigned int ch_bits = 0; |
1128 | for (j = 0; j < channels; j++) { | 1131 | for (j = 0; j < channels; j++) { |
1129 | unsigned int mask = snd_usb_combine_bytes(ftr + 6 + csize * (j+1), csize); | 1132 | unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize); |
1130 | if (mask & (1 << i)) | 1133 | if (mask & (1 << i)) |
1131 | ch_bits |= (1 << j); | 1134 | ch_bits |= (1 << j); |
1132 | } | 1135 | } |
1133 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1136 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ |
1134 | build_feature_ctl(state, ftr, ch_bits, i, &iterm, unitid); | 1137 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid); |
1135 | if (master_bits & (1 << i)) | 1138 | if (master_bits & (1 << i)) |
1136 | build_feature_ctl(state, ftr, 0, i, &iterm, unitid); | 1139 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid); |
1137 | } | 1140 | } |
1138 | 1141 | ||
1139 | return 0; | 1142 | return 0; |
@@ -1780,7 +1783,7 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) | |||
1780 | */ | 1783 | */ |
1781 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | 1784 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) |
1782 | { | 1785 | { |
1783 | unsigned char *desc; | 1786 | struct uac_output_terminal_descriptor_v1 *desc; |
1784 | struct mixer_build state; | 1787 | struct mixer_build state; |
1785 | int err; | 1788 | int err; |
1786 | const struct usbmix_ctl_map *map; | 1789 | const struct usbmix_ctl_map *map; |
@@ -1805,13 +1808,13 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1805 | 1808 | ||
1806 | desc = NULL; | 1809 | desc = NULL; |
1807 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { | 1810 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { |
1808 | if (desc[0] < 9) | 1811 | if (desc->bLength < 9) |
1809 | continue; /* invalid descriptor? */ | 1812 | continue; /* invalid descriptor? */ |
1810 | set_bit(desc[3], state.unitbitmap); /* mark terminal ID as visited */ | 1813 | set_bit(desc->bTerminalID, state.unitbitmap); /* mark terminal ID as visited */ |
1811 | state.oterm.id = desc[3]; | 1814 | state.oterm.id = desc->bTerminalID; |
1812 | state.oterm.type = combine_word(&desc[4]); | 1815 | state.oterm.type = le16_to_cpu(desc->wTerminalType); |
1813 | state.oterm.name = desc[8]; | 1816 | state.oterm.name = desc->iTerminal; |
1814 | err = parse_audio_unit(&state, desc[7]); | 1817 | err = parse_audio_unit(&state, desc->bSourceID); |
1815 | if (err < 0) | 1818 | if (err < 0) |
1816 | return err; | 1819 | return err; |
1817 | } | 1820 | } |