1 use std::{fmt, slice};
2
3 use libusb1_sys::*;
4
5 use crate::interface_descriptor::{self, Interface};
6
7 /// Describes a configuration.
8 pub struct ConfigDescriptor {
9 descriptor: *const libusb_config_descriptor,
10 }
11
12 impl Drop for ConfigDescriptor {
drop(&mut self)13 fn drop(&mut self) {
14 unsafe {
15 libusb_free_config_descriptor(self.descriptor);
16 }
17 }
18 }
19
20 unsafe impl Sync for ConfigDescriptor {}
21 unsafe impl Send for ConfigDescriptor {}
22
23 impl ConfigDescriptor {
24 /// Returns the size of the descriptor in bytes
length(&self) -> u825 pub fn length(&self) -> u8 {
26 unsafe { (*self.descriptor).bLength }
27 }
28
29 /// Returns the total length in bytes of data returned for this configuration: all interfaces and endpoints
total_length(&self) -> u1630 pub fn total_length(&self) -> u16 {
31 unsafe { (*self.descriptor).wTotalLength }
32 }
33
34 /// Returns the descriptor type
descriptor_type(&self) -> u835 pub fn descriptor_type(&self) -> u8 {
36 unsafe { (*self.descriptor).bDescriptorType }
37 }
38
39 /// Returns the configuration number.
number(&self) -> u840 pub fn number(&self) -> u8 {
41 unsafe { (*self.descriptor).bConfigurationValue }
42 }
43
44 /// Returns the device's maximum power consumption (in milliamps) in this configuration.
max_power(&self) -> u1645 pub fn max_power(&self) -> u16 {
46 unsafe { u16::from((*self.descriptor).bMaxPower) * 2 }
47 }
48
49 /// Indicates if the device is self-powered in this configuration.
self_powered(&self) -> bool50 pub fn self_powered(&self) -> bool {
51 unsafe { (*self.descriptor).bmAttributes & 0x40 != 0 }
52 }
53
54 /// Indicates if the device has remote wakeup capability in this configuration.
remote_wakeup(&self) -> bool55 pub fn remote_wakeup(&self) -> bool {
56 unsafe { (*self.descriptor).bmAttributes & 0x20 != 0 }
57 }
58
59 /// Returns the index of the string descriptor that describes the configuration.
description_string_index(&self) -> Option<u8>60 pub fn description_string_index(&self) -> Option<u8> {
61 unsafe {
62 match (*self.descriptor).iConfiguration {
63 0 => None,
64 n => Some(n),
65 }
66 }
67 }
68
69 /// Returns the number of interfaces for this configuration.
num_interfaces(&self) -> u870 pub fn num_interfaces(&self) -> u8 {
71 unsafe { (*self.descriptor).bNumInterfaces }
72 }
73
74 /// Returns a collection of the configuration's interfaces.
interfaces(&self) -> Interfaces75 pub fn interfaces(&self) -> Interfaces {
76 let interfaces = unsafe {
77 slice::from_raw_parts(
78 (*self.descriptor).interface,
79 (*self.descriptor).bNumInterfaces as usize,
80 )
81 };
82
83 Interfaces {
84 iter: interfaces.iter(),
85 }
86 }
87
88 /// Returns the unknown 'extra' bytes that libusb does not understand.
extra(&self) -> &[u8]89 pub fn extra(&self) -> &[u8] {
90 unsafe {
91 match (*self.descriptor).extra_length {
92 len if len > 0 => slice::from_raw_parts((*self.descriptor).extra, len as usize),
93 _ => &[],
94 }
95 }
96 }
97 }
98
99 impl fmt::Debug for ConfigDescriptor {
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>100 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
101 let mut debug = fmt.debug_struct("ConfigDescriptor");
102
103 let descriptor: &libusb_config_descriptor = unsafe { &*self.descriptor };
104
105 debug.field("bLength", &descriptor.bLength);
106 debug.field("bDescriptorType", &descriptor.bDescriptorType);
107 debug.field("wTotalLength", &descriptor.wTotalLength);
108 debug.field("bNumInterfaces", &descriptor.bNumInterfaces);
109 debug.field("bConfigurationValue", &descriptor.bConfigurationValue);
110 debug.field("iConfiguration", &descriptor.iConfiguration);
111 debug.field("bmAttributes", &descriptor.bmAttributes);
112 debug.field("bMaxPower", &descriptor.bMaxPower);
113 debug.field("extra", &self.extra());
114
115 debug.finish()
116 }
117 }
118
119 /// Iterator over a configuration's interfaces.
120 pub struct Interfaces<'a> {
121 iter: slice::Iter<'a, libusb_interface>,
122 }
123
124 impl<'a> Iterator for Interfaces<'a> {
125 type Item = Interface<'a>;
126
next(&mut self) -> Option<Interface<'a>>127 fn next(&mut self) -> Option<Interface<'a>> {
128 self.iter
129 .next()
130 .map(|interface| unsafe { interface_descriptor::from_libusb(interface) })
131 }
132
size_hint(&self) -> (usize, Option<usize>)133 fn size_hint(&self) -> (usize, Option<usize>) {
134 self.iter.size_hint()
135 }
136 }
137
138 #[doc(hidden)]
from_libusb(config: *const libusb_config_descriptor) -> ConfigDescriptor139 pub(crate) unsafe fn from_libusb(config: *const libusb_config_descriptor) -> ConfigDescriptor {
140 ConfigDescriptor { descriptor: config }
141 }
142
143 #[cfg(test)]
144 mod test {
145 use std::mem::ManuallyDrop;
146
147 // The Drop trait impl calls libusb_free_config_descriptor(), which would attempt to free
148 // unallocated memory for a stack-allocated config descriptor. Allocating a config descriptor
149 // is not a simple malloc()/free() inside libusb. Mimicking libusb's allocation would be
150 // error-prone, difficult to maintain, and provide little benefit for the tests. It's easier to
151 // use mem::forget() to prevent the Drop trait impl from running. The config descriptor passed
152 // as `$config` should be stack-allocated to prevent memory leaks in the test suite.
153 macro_rules! with_config {
154 ($name:ident : $config:expr => $body:block) => {{
155 let config = $config;
156 let $name = ManuallyDrop::new(unsafe { super::from_libusb(&config) });
157 $body;
158 }};
159 }
160
161 #[test]
it_has_number()162 fn it_has_number() {
163 with_config!(config: config_descriptor!(bConfigurationValue: 42) => {
164 assert_eq!(42, config.number());
165 });
166 }
167
168 #[test]
it_has_max_power()169 fn it_has_max_power() {
170 with_config!(config: config_descriptor!(bMaxPower: 21) => {
171 assert_eq!(42, config.max_power());
172 });
173 }
174
175 #[test]
it_interprets_self_powered_bit_in_attributes()176 fn it_interprets_self_powered_bit_in_attributes() {
177 with_config!(config: config_descriptor!(bmAttributes: 0b0000_0000) => {
178 assert_eq!(false, config.self_powered());
179 });
180
181 with_config!(config: config_descriptor!(bmAttributes: 0b0100_0000) => {
182 assert_eq!(true, config.self_powered());
183 });
184 }
185
186 #[test]
it_interprets_remote_wakeup_bit_in_attributes()187 fn it_interprets_remote_wakeup_bit_in_attributes() {
188 with_config!(config: config_descriptor!(bmAttributes: 0b0000_0000) => {
189 assert_eq!(false, config.remote_wakeup());
190 });
191
192 with_config!(config: config_descriptor!(bmAttributes: 0b0010_0000) => {
193 assert_eq!(true, config.remote_wakeup());
194 });
195 }
196
197 #[test]
it_has_description_string_index()198 fn it_has_description_string_index() {
199 with_config!(config: config_descriptor!(iConfiguration: 42) => {
200 assert_eq!(Some(42), config.description_string_index());
201 });
202 }
203
204 #[test]
it_handles_missing_description_string_index()205 fn it_handles_missing_description_string_index() {
206 with_config!(config: config_descriptor!(iConfiguration: 0) => {
207 assert_eq!(None, config.description_string_index());
208 });
209 }
210
211 #[test]
it_has_num_interfaces()212 fn it_has_num_interfaces() {
213 let interface1 = interface!(interface_descriptor!(bInterfaceNumber: 1));
214 let interface2 = interface!(interface_descriptor!(bInterfaceNumber: 2));
215
216 with_config!(config: config_descriptor!(interface1, interface2) => {
217 assert_eq!(2, config.num_interfaces());
218 });
219 }
220
221 #[test]
it_has_interfaces()222 fn it_has_interfaces() {
223 let interface = interface!(interface_descriptor!(bInterfaceNumber: 1));
224
225 with_config!(config: config_descriptor!(interface) => {
226 let interface_numbers = config.interfaces().map(|interface| {
227 interface.number()
228 }).collect::<Vec<_>>();
229
230 assert_eq!(vec![1], interface_numbers);
231 });
232 }
233
234 // Successful compilation shows that the lifetime of the endpoint descriptor(s) is the same
235 // as the lifetime of the config descriptor.
236 #[test]
it_had_interfaces_with_endpoints()237 fn it_had_interfaces_with_endpoints() {
238 let endpoint1 = endpoint_descriptor!(bEndpointAddress: 0x81);
239 let endpoint2 = endpoint_descriptor!(bEndpointAddress: 0x01);
240 let endpoint3 = endpoint_descriptor!(bEndpointAddress: 0x02);
241 let interface1 = interface!(interface_descriptor!(endpoint1, endpoint2));
242 let interface2 = interface!(interface_descriptor!(endpoint3));
243
244 with_config!(config: config_descriptor!(interface1, interface2) => {
245 // Exists only to name config's lifetime.
246 fn named_lifetime<'a>(config: &'a super::ConfigDescriptor) {
247 let addresses: Vec<_> = config.interfaces().flat_map(|intf| intf.descriptors()).flat_map(|desc| desc.endpoint_descriptors()).map(|ep| ep.address()).collect();
248 assert_eq!(addresses, &[0x81, 0x01, 0x02]);
249 let desc: crate::InterfaceDescriptor<'a> = config.interfaces().flat_map(|intf| intf.descriptors()).next().expect("There's one interface");
250 let _: crate::EndpointDescriptor<'a> = desc.endpoint_descriptors().next().expect("There's one endpoint");
251 }
252 named_lifetime(&*config);
253 })
254 }
255 }
256