Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(627)

Side by Side Diff: media/midi/usb_midi_descriptor_parser.cc

Issue 105043008: Introduce USB MIDI descriptor parser (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/midi/usb_midi_descriptor_parser.h"
6
7 #include "base/logging.h"
8
9 namespace media {
10
11 namespace {
12
13 // The constants below are specified in USB spec, USB audio spec
14 // and USB midi spec.
15
16 enum DescriptorType {
17 TYPE_DEVICE = 1,
18 TYPE_CONFIGURATION = 2,
19 TYPE_STRING = 3,
20 TYPE_INTERFACE = 4,
21 TYPE_ENDPOINT = 5,
22 TYPE_DEVICE_QUALIFIER = 6,
23 TYPE_OTHER_SPEED_CONFIGURATION = 7,
24 TYPE_INTERFACE_POWER = 8,
25
26 TYPE_CS_INTERFACE = 36,
27 TYPE_CS_ENDPOINT = 37,
28 };
29
30 enum DescriptorSubType {
31 SUBTYPE_MS_DESCRIPTOR_UNDEFINED = 0,
32 SUBTYPE_MS_HEADER = 1,
33 SUBTYPE_MIDI_IN_JACK = 2,
34 SUBTYPE_MIDI_OUT_JACK = 3,
35 SUBTYPE_ELEMENT = 4,
36 };
37
38 enum JackType {
39 JACK_TYPE_UNDEFINED = 0,
40 JACK_TYPE_EMBEDDED = 1,
41 JACK_TYPE_EXTERNAL = 2,
42 };
43
44 const uint8 kAudioInterfaceClass = 1;
45 const uint8 kAudioMidiInterfaceSubclass = 3;
46
47 } // namespace
48
49 UsbMidiDescriptorParser::UsbMidiDescriptorParser()
50 : is_parsing_usb_midi_interface_(false),
51 current_endpoint_address_(0),
52 current_cable_number_(0) {}
53
54 UsbMidiDescriptorParser::~UsbMidiDescriptorParser() {}
55
56 bool UsbMidiDescriptorParser::Parse(UsbMidiDevice* device,
57 const uint8* data,
58 size_t size) {
59 Clear();
60 bool result = ParseInternal(device, data, size);
61 if (result)
62 ClearExceptJacks();
63 else
64 Clear();
65 return result;
66 }
67
68 bool UsbMidiDescriptorParser::ParseInternal(UsbMidiDevice* device,
69 const uint8* data,
70 size_t size) {
71 DCHECK(jacks_.empty());
72 const uint8* current = data;
73 while (current < &data[size]) {
74 uint8 length = current[0];
75 if (length <= 1) {
76 DVLOG(1) << "Descriptor Type is not accessible.";
77 return false;
78 }
79 if (&current[length] > &data[size]) {
80 DVLOG(1) << "The header size is incorrect.";
81 return false;
82 }
83 DescriptorType descriptor_type = static_cast<DescriptorType>(current[1]);
84 switch (descriptor_type) {
85 case TYPE_INTERFACE:
86 if (!ParseInterface(device, current, length))
87 return false;
88 break;
89 case TYPE_CS_INTERFACE:
90 if (!ParseCSInterface(device, current, length))
91 return false;
92 break;
93 case TYPE_ENDPOINT:
94 if (!ParseEndpoint(device, current, length))
95 return false;
96 break;
97 case TYPE_CS_ENDPOINT:
98 if (!ParseCSEndpoint(device, current, length))
99 return false;
100 break;
101 default:
Takashi Toyoshima 2013/12/19 08:33:14 Need a comment to skip uninteresting types which i
yhirano 2013/12/19 08:39:21 Done.
102 break;
103 }
104 current += length;
105 }
106 return true;
107 }
108
109 bool UsbMidiDescriptorParser::ParseInterface(UsbMidiDevice* device,
110 const uint8* data,
111 size_t size) {
112 if (size != 9) {
113 DVLOG(1) << "INTERFACE header size is incorrect.";
114 return false;
115 }
116 incomplete_jacks_.clear();
117
118 uint8 interface_class = data[5];
119 uint8 interface_subclass = data[6];
120
121 // All descriptors of endpoints contained in this interface
122 // precede the next INTERFACE descriptor.
123 is_parsing_usb_midi_interface_ =
124 (interface_class == kAudioInterfaceClass &&
125 interface_subclass == kAudioMidiInterfaceSubclass);
126 return true;
127 }
128
129 bool UsbMidiDescriptorParser::ParseCSInterface(UsbMidiDevice* device,
130 const uint8* data,
131 size_t size) {
132 if (!is_parsing_usb_midi_interface_)
133 return true;
134
135 // Descriptor Type and Descriptor Subtype should be accessible.
136 if (size <= 2) {
137 DVLOG(1) << "CS_INTERFACE header size is incorrect.";
138 return false;
139 }
140
141 DescriptorSubType subtype = static_cast<DescriptorSubType>(data[2]);
142
143 switch (subtype) {
144 case SUBTYPE_MIDI_IN_JACK:
145 // FALL_THROUGH
146 case SUBTYPE_MIDI_OUT_JACK: {
147 if (size < 6) {
148 DVLOG(1) << "CS_INTERFACE (MIDI JACK) header size is incorrect.";
149 return false;
150 }
151 uint8 jack_type = data[3];
152 uint8 id = data[4];
153 if (jack_type == JACK_TYPE_EMBEDDED) {
154 // We can't determine the associated endpoint now.
155 incomplete_jacks_.insert(
156 std::make_pair(id, UsbMidiJack(device, id, 0, 0)));
157 }
158 break;
159 }
160 default:
161 break;
162 }
163 return true;
164 }
165
166 bool UsbMidiDescriptorParser::ParseEndpoint(UsbMidiDevice* device,
167 const uint8* data,
168 size_t size) {
169 if (!is_parsing_usb_midi_interface_)
170 return true;
171
172 if (size < 4) {
173 DVLOG(1) << "ENDPOINT header size is incorrect.";
174 return false;
175 }
176 current_endpoint_address_ = data[2];
177 current_cable_number_ = 0;
178 return true;
179 }
180
181 bool UsbMidiDescriptorParser::ParseCSEndpoint(UsbMidiDevice* device,
182 const uint8* data,
183 size_t size) {
184 if (!is_parsing_usb_midi_interface_)
185 return true;
186 // CS_ENDPOINT must be of size 4 + n where n is the number of associated
187 // jacks.
188 if (size < 4) {
189 DVLOG(1) << "CS_ENDPOINT header size is incorrect.";
190 return false;
191 }
192 uint8 num_jacks = data[3];
193 if (size != 4 + num_jacks) {
194 DVLOG(1) << "CS_ENDPOINT header size is incorrect.";
195 return false;
196 }
197
198 for (size_t i = 0; i < num_jacks; ++i) {
199 uint8 jack = data[4 + i];
200 base::hash_map<uint8, UsbMidiJack>::iterator it =
201 incomplete_jacks_.find(jack);
202 if (it == incomplete_jacks_.end()) {
203 DVLOG(1) << "A non-existing MIDI jack is associated.";
204 return false;
205 }
206 if (current_cable_number_ >= 0x10) {
207 DVLOG(1) << "Cable number should range from 0x0 to 0xf.";
208 return false;
209 }
210 // CS_ENDPOINT follows ENDPOINT and hence we can use the following
211 // member variables.
212 it->second.cable_number = current_cable_number_++;
213 it->second.endpoint_address = current_endpoint_address_;
214 jacks_.push_back(it->second);
215 incomplete_jacks_.erase(it);
216 }
217 return true;
218 }
219
220 void UsbMidiDescriptorParser::Clear() {
221 ClearExceptJacks();
222 jacks_.clear();
223 }
224
225 void UsbMidiDescriptorParser::ClearExceptJacks() {
226 is_parsing_usb_midi_interface_ = false;
227 current_endpoint_address_ = 0;
228 current_cable_number_ = 0;
229 incomplete_jacks_.clear();
230 }
231
232 } // namespace media
OLDNEW
« no previous file with comments | « media/midi/usb_midi_descriptor_parser.h ('k') | media/midi/usb_midi_descriptor_parser_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698