2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
13 import usb_descriptors
16 device_desc
= usb_descriptors
.DeviceDescriptor(
17 idVendor
=0x18D1, # Google Inc.
26 fs_config_desc
= usb_descriptors
.ConfigurationDescriptor(
30 fs_interface_desc
= usb_descriptors
.InterfaceDescriptor(
33 fs_config_desc
.AddInterface(fs_interface_desc
)
35 fs_bulk_in_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
36 bEndpointAddress
=0x01,
37 bmAttributes
=usb_constants
.TransferType
.BULK
,
41 fs_interface_desc
.AddEndpoint(fs_bulk_in_endpoint_desc
)
43 fs_bulk_out_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
44 bEndpointAddress
=0x81,
45 bmAttributes
=usb_constants
.TransferType
.BULK
,
49 fs_interface_desc
.AddEndpoint(fs_bulk_out_endpoint_desc
)
51 fs_alt_interface_desc
= usb_descriptors
.InterfaceDescriptor(
55 fs_config_desc
.AddInterface(fs_alt_interface_desc
)
57 fs_interrupt_in_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
58 bEndpointAddress
=0x01,
59 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
63 fs_alt_interface_desc
.AddEndpoint(fs_interrupt_in_endpoint_desc
)
65 fs_interrupt_out_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
66 bEndpointAddress
=0x81,
67 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
71 fs_alt_interface_desc
.AddEndpoint(fs_interrupt_out_endpoint_desc
)
73 hs_config_desc
= usb_descriptors
.ConfigurationDescriptor(
77 hs_interface_desc
= usb_descriptors
.InterfaceDescriptor(
80 hs_config_desc
.AddInterface(hs_interface_desc
)
82 hs_bulk_in_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
83 bEndpointAddress
=0x01,
84 bmAttributes
=usb_constants
.TransferType
.BULK
,
88 hs_interface_desc
.AddEndpoint(hs_bulk_in_endpoint_desc
)
90 hs_bulk_out_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
91 bEndpointAddress
=0x81,
92 bmAttributes
=usb_constants
.TransferType
.BULK
,
96 hs_interface_desc
.AddEndpoint(hs_bulk_out_endpoint_desc
)
98 hs_alt_interface_desc
= usb_descriptors
.InterfaceDescriptor(
102 hs_config_desc
.AddInterface(hs_alt_interface_desc
)
104 hs_interrupt_in_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
105 bEndpointAddress
=0x01,
106 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
110 hs_alt_interface_desc
.AddEndpoint(hs_interrupt_in_endpoint_desc
)
112 hs_interrupt_out_endpoint_desc
= usb_descriptors
.EndpointDescriptor(
113 bEndpointAddress
=0x81,
114 bmAttributes
=usb_constants
.TransferType
.INTERRUPT
,
118 hs_alt_interface_desc
.AddEndpoint(hs_interrupt_out_endpoint_desc
)
121 class GadgetTest(unittest
.TestCase
):
123 def test_get_descriptors(self
):
124 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
125 self
.assertEquals(g
.GetDeviceDescriptor(), device_desc
)
126 self
.assertEquals(g
.GetFullSpeedConfigurationDescriptor(), fs_config_desc
)
127 self
.assertEquals(g
.GetHighSpeedConfigurationDescriptor(), hs_config_desc
)
128 with self
.assertRaisesRegexp(RuntimeError, 'not connected'):
129 g
.GetConfigurationDescriptor()
131 def test_connect_full_speed(self
):
132 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
133 g
.Connected(mock
.Mock(), usb_constants
.Speed
.FULL
)
134 self
.assertTrue(g
.IsConnected())
135 self
.assertEquals(g
.GetSpeed(), usb_constants
.Speed
.FULL
)
136 self
.assertEquals(g
.GetConfigurationDescriptor(), fs_config_desc
)
138 self
.assertFalse(g
.IsConnected())
140 def test_connect_high_speed(self
):
141 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
142 g
.Connected(mock
.Mock(), usb_constants
.Speed
.HIGH
)
143 self
.assertTrue(g
.IsConnected())
144 self
.assertEquals(g
.GetSpeed(), usb_constants
.Speed
.HIGH
)
145 self
.assertEquals(g
.GetConfigurationDescriptor(), hs_config_desc
)
147 self
.assertFalse(g
.IsConnected())
149 def test_string_index_out_of_range(self
):
150 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
151 with self
.assertRaisesRegexp(ValueError, 'index out of range'):
152 g
.AddStringDescriptor(0, 'Hello world!')
154 def test_language_id_out_of_range(self
):
155 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
156 with self
.assertRaisesRegexp(ValueError, 'language code out of range'):
157 g
.AddStringDescriptor(1, 'Hello world!', lang
=-1)
159 def test_get_languages(self
):
160 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
161 g
.AddStringDescriptor(1, 'Hello world!')
162 desc
= g
.ControlRead(0x80, 6, 0x0300, 0, 255)
163 self
.assertEquals(desc
, '\x04\x03\x09\x04')
165 def test_get_string_descriptor(self
):
166 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
167 g
.AddStringDescriptor(1, 'Hello world!')
168 desc
= g
.ControlRead(0x80, 6, 0x0301, 0x0409, 255)
169 self
.assertEquals(desc
, '\x1A\x03H\0e\0l\0l\0o\0 \0w\0o\0r\0l\0d\0!\0')
171 def test_get_missing_string_descriptor(self
):
172 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
173 g
.AddStringDescriptor(1, 'Hello world!')
174 desc
= g
.ControlRead(0x80, 6, 0x0302, 0x0409, 255)
175 self
.assertEquals(desc
, None)
177 def test_get_missing_string_language(self
):
178 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
179 g
.AddStringDescriptor(1, 'Hello world!')
180 desc
= g
.ControlRead(0x80, 6, 0x0301, 0x040C, 255)
181 self
.assertEquals(desc
, None)
183 def test_class_and_vendor_transfers(self
):
184 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
185 self
.assertIsNone(g
.ControlRead(0xA0, 0, 0, 0, 0))
186 self
.assertIsNone(g
.ControlRead(0xC0, 0, 0, 0, 0))
187 self
.assertIsNone(g
.ControlWrite(0x20, 0, 0, 0, ''))
188 self
.assertIsNone(g
.ControlWrite(0x40, 0, 0, 0, ''))
190 def test_set_configuration(self
):
191 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
193 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
194 g
.ControlWrite(0, 9, 1, 0, 0)
195 chip
.StartEndpoint
.assert_has_calls([
196 mock
.call(hs_bulk_in_endpoint_desc
),
197 mock
.call(hs_bulk_out_endpoint_desc
)
200 def test_set_configuration_zero(self
):
201 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
203 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
204 g
.ControlWrite(0, 9, 1, 0, 0)
205 chip
.StartEndpoint
.reset_mock()
206 g
.ControlWrite(0, 9, 0, 0, 0)
207 chip
.StopEndpoint
.assert_has_calls([
212 def test_set_bad_configuration(self
):
213 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
214 g
.Connected(mock
.Mock(), usb_constants
.Speed
.HIGH
)
215 self
.assertIsNone(g
.ControlWrite(0, 9, 2, 0, 0))
217 def test_set_interface(self
):
218 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
220 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
221 self
.assertTrue(g
.ControlWrite(0, 9, 1, 0, 0))
223 self
.assertTrue(g
.ControlWrite(1, 11, 1, 0, 0))
224 chip
.StopEndpoint
.assert_has_calls([
228 chip
.StartEndpoint
.assert_has_calls([
229 mock
.call(hs_interrupt_in_endpoint_desc
),
230 mock
.call(hs_interrupt_out_endpoint_desc
)
233 self
.assertTrue(g
.ControlWrite(1, 11, 0, 0, 0))
234 chip
.StopEndpoint
.assert_has_calls([
238 chip
.StartEndpoint
.assert_has_calls([
239 mock
.call(hs_bulk_in_endpoint_desc
),
240 mock
.call(hs_bulk_out_endpoint_desc
)
243 def test_set_bad_interface(self
):
244 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
245 g
.Connected(mock
.Mock(), usb_constants
.Speed
.HIGH
)
246 self
.assertTrue(g
.ControlWrite(0, 9, 1, 0, 0))
247 self
.assertIsNone(g
.ControlWrite(1, 11, 0, 1, 0))
249 def test_send_packet(self
):
250 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
252 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
253 g
.SendPacket(0x81, 'Hello world!')
254 chip
.SendPacket
.assert_called_once_with(0x81, 'Hello world!')
256 def test_send_packet_disconnected(self
):
257 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
258 with self
.assertRaisesRegexp(RuntimeError, 'not connected'):
259 g
.SendPacket(0x81, 'Hello world!')
260 g
.Connected(mock
.Mock(), usb_constants
.Speed
.HIGH
)
261 g
.SendPacket(0x81, 'Hello world!')
263 with self
.assertRaisesRegexp(RuntimeError, 'not connected'):
264 g
.SendPacket(0x81, 'Hello world!')
266 def test_send_invalid_endpoint(self
):
267 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
269 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
270 with self
.assertRaisesRegexp(ValueError, 'non-input endpoint'):
271 g
.SendPacket(0x01, 'Hello world!')
273 def test_receive_packet(self
):
274 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
275 self
.assertIsNone(g
.ReceivePacket(0x01, 'Hello world!'))
277 def test_halt_endpoint(self
):
278 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
280 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
282 chip
.HaltEndpoint
.assert_called_once_with(0x01)
284 def test_get_microsoft_os_string_descriptor(self
):
285 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
286 g
.EnableMicrosoftOSDescriptorsV1(vendor_code
=0x42)
287 os_string_descriptor
= g
.ControlRead(0x80,
288 usb_constants
.Request
.GET_DESCRIPTOR
,
292 self
.assertEqual(os_string_descriptor
,
293 "\x12\x03M\x00S\x00F\x00T\x001\x000\x000\x00\x42\x00")
295 def test_get_microsoft_os_compat_id_descriptor(self
):
296 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
297 g
.EnableMicrosoftOSDescriptorsV1(vendor_code
=0x42)
298 g
.SetMicrosoftCompatId(0, 'WINUSB')
300 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
302 expected_compatid_header
= \
303 "\x28\x00\x00\x00\x00\x01\x04\x00\x01\0\0\0\0\0\0\0"
304 compatid_header
= g
.ControlRead(0xC0, 0x42, 0x0000, 0x0004, 0x0010)
305 self
.assertEqual(compatid_header
, expected_compatid_header
)
307 compatid_descriptor
= g
.ControlRead(0xC0, 0x42, 0x0000, 0x0004, 0x0028)
308 self
.assertEqual(compatid_descriptor
,
309 expected_compatid_header
+
310 "\x00\x01WINUSB\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
312 def test_get_bos_descriptor(self
):
313 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
314 self
.assertIsNone(g
.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 5))
316 container_id
= uuid
.uuid4()
317 g
.AddDeviceCapabilityDescriptor(usb_descriptors
.ContainerIdDescriptor(
318 ContainerID
=container_id
.bytes_le
))
319 bos_descriptor_header
= g
.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 5)
320 self
.assertEquals('\x05\x0F\x19\x00\x01', bos_descriptor_header
)
322 bos_descriptor
= g
.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 25)
324 '\x05\x0F\x19\x00\x01\x14\x10\x04\x00' + container_id
.bytes_le
,
327 def test_get_microsoft_os_20_descriptor_set(self
):
328 g
= gadget
.Gadget(device_desc
, fs_config_desc
, hs_config_desc
)
329 g
.EnableMicrosoftOSDescriptorsV2(vendor_code
=0x42)
330 g
.SetMicrosoftCompatId(0, 'WINUSB')
332 g
.Connected(chip
, usb_constants
.Speed
.HIGH
)
334 bos_descriptor
= g
.ControlRead(0x80, 0x06, 0x0F00, 0x0000, 33)
336 '\x05\x0F\x21\x00\x01' +
338 uuid
.UUID('{D8DD60DF-4589-4CC7-9CD2-659D9E648A9F}').bytes_le
+
339 '\x00\x00\x03\x06\x2E\x00\x42\x00',
342 descriptor_set
= g
.ControlRead(0xC0, 0x42, 0x0000, 0x0007, 48)
344 '\x0A\x00\x00\x00\x00\x00\x03\x06\x2E\x00' +
345 '\x08\x00\x01\x00\x00\x00\x24\x00' +
346 '\x08\x00\x02\x00\x00\x00\x1C\x00' +
347 '\x14\x00\x03\x00WINUSB\0\0\0\0\0\0\0\0\0\0',
351 if __name__
== '__main__':