Skip to main content

rusb/
device_handle.rs

1use std::{
2    fmt::{self, Debug},
3    mem,
4    ptr::NonNull,
5    sync::Mutex,
6    time::Duration,
7};
8
9use libc::{c_int, c_uchar, c_uint};
10use libusb1_sys::{constants::*, *};
11
12use crate::{
13    config_descriptor::ConfigDescriptor,
14    device::{self, Device},
15    device_descriptor::DeviceDescriptor,
16    error::{self, Error},
17    fields::{request_type, Direction, Recipient, RequestType},
18    interface_descriptor::InterfaceDescriptor,
19    language::Language,
20    UsbContext,
21};
22
23/// Bit set representing claimed USB interfaces.
24#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
25struct ClaimedInterfaces {
26    inner: [u128; 2],
27}
28
29impl ClaimedInterfaces {
30    /// Create a new bit set.
31    fn new() -> Self {
32        Self { inner: [0, 0] }
33    }
34
35    fn get_index_and_mask(interface: u8) -> (usize, u128) {
36        ((interface / 128) as usize, 1 << (interface % 128))
37    }
38
39    /// Mark `interface` as claimed.
40    fn insert(&mut self, interface: u8) {
41        let (index, mask) = ClaimedInterfaces::get_index_and_mask(interface);
42        self.inner[index] |= mask;
43    }
44
45    /// Mark `interface` as not claimed.
46    fn remove(&mut self, interface: u8) {
47        let (index, mask) = ClaimedInterfaces::get_index_and_mask(interface);
48        self.inner[index] &= !mask;
49    }
50
51    /// Returns true if this set contains `interface`.
52    fn contains(&self, interface: u8) -> bool {
53        let (index, mask) = ClaimedInterfaces::get_index_and_mask(interface);
54        self.inner[index] & mask != 0
55    }
56
57    /// Returns a count of the interfaces contained in this set.
58    fn size(&self) -> usize {
59        self.inner.iter().map(|v| v.count_ones()).sum::<u32>() as usize
60    }
61
62    /// Returns an iterator over the interfaces in this set.
63    fn iter(&self) -> ClaimedInterfacesIter {
64        ClaimedInterfacesIter::new(self)
65    }
66}
67
68/// Iterator over interfaces.
69struct ClaimedInterfacesIter<'a> {
70    // Next interface to check as a possible value to return from the interator.
71    index: u16,
72
73    // Number of elements remaining in this iterator.
74    remaining: usize,
75
76    // The ClaimedInterfaces object that we're iterating over.
77    source: &'a ClaimedInterfaces,
78}
79
80impl ClaimedInterfacesIter<'_> {
81    /// Create a new iterator over the interfaces in `source`.
82    fn new(source: &ClaimedInterfaces) -> ClaimedInterfacesIter {
83        ClaimedInterfacesIter {
84            index: 0,
85            remaining: source.size(),
86            source,
87        }
88    }
89}
90
91impl<'a> Iterator for ClaimedInterfacesIter<'a> {
92    type Item = u8;
93
94    fn next(&mut self) -> Option<u8> {
95        while self.index <= u8::MAX as u16 {
96            let index = self.index as u8;
97            let contains = self.source.contains(index);
98            self.index += 1;
99            if contains {
100                self.remaining -= 1;
101                return Some(index);
102            }
103        }
104        None
105    }
106
107    fn size_hint(&self) -> (usize, Option<usize>) {
108        (self.remaining, Some(self.remaining))
109    }
110}
111
112/// A handle to an open USB device.
113pub struct DeviceHandle<T: UsbContext> {
114    context: T,
115    handle: Option<NonNull<libusb_device_handle>>,
116    interfaces: Mutex<ClaimedInterfaces>,
117}
118
119impl<T: UsbContext> Drop for DeviceHandle<T> {
120    /// Closes the device.
121    fn drop(&mut self) {
122        unsafe {
123            let interfaces = self.interfaces.lock().unwrap();
124            for iface in interfaces.iter() {
125                libusb_release_interface(self.as_raw(), iface as c_int);
126            }
127
128            if let Some(handle) = self.handle {
129                libusb_close(handle.as_ptr());
130            }
131        }
132    }
133}
134
135unsafe impl<T: UsbContext> Send for DeviceHandle<T> {}
136unsafe impl<T: UsbContext> Sync for DeviceHandle<T> {}
137
138impl<T: UsbContext> Debug for DeviceHandle<T> {
139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        f.debug_struct("DeviceHandle")
141            .field("device", &self.device())
142            .field("handle", &self.handle)
143            .field("interfaces", &*self.interfaces.lock().unwrap())
144            .finish()
145    }
146}
147
148impl<T: UsbContext + PartialEq> PartialEq for DeviceHandle<T> {
149    fn eq(&self, other: &Self) -> bool {
150        self.context == other.context
151            && self.handle == other.handle
152            && *self.interfaces.lock().unwrap() == *other.interfaces.lock().unwrap()
153    }
154}
155
156impl<T: UsbContext + PartialEq> Eq for DeviceHandle<T> {}
157
158impl<T: UsbContext> DeviceHandle<T> {
159    /// Get the raw libusb_device_handle pointer, for advanced use in unsafe code.
160    ///
161    /// This structure tracks claimed interfaces, and will get out if sync if interfaces are
162    /// manipulated externally. Use only libusb endpoint IO functions.
163    pub fn as_raw(&self) -> *mut libusb_device_handle {
164        // Safety: handle is Some() after initialization
165        match self.handle {
166            Some(it) => it.as_ptr(),
167            _ => unreachable!(),
168        }
169    }
170
171    /// Consumes the `DeviceHandle`, returning the raw libusb_device_handle
172    /// pointer, for advanced use in unsafe code.
173    ///
174    /// # Safety
175    ///
176    /// Panics if you have any claimed interfaces on this handle.
177    pub fn into_raw(mut self) -> *mut libusb_device_handle {
178        assert_eq!(self.interfaces.lock().unwrap().size(), 0);
179        match self.handle.take() {
180            Some(it) => it.as_ptr(),
181            _ => unreachable!(),
182        }
183    }
184
185    /// Get the context associated with this device
186    pub fn context(&self) -> &T {
187        &self.context
188    }
189
190    /// Get the device associated to this handle
191    pub fn device(&self) -> Device<T> {
192        unsafe {
193            device::Device::from_libusb(
194                self.context.clone(),
195                std::ptr::NonNull::new_unchecked(libusb_get_device(self.as_raw())),
196            )
197        }
198    }
199
200    /// # Safety
201    ///
202    /// Converts an existing `libusb_device_handle` pointer into a `DeviceHandle<T>`.
203    /// `handle` must be a pointer to a valid `libusb_device_handle`. Rusb assumes ownership of the handle, and will close it on `drop`.
204    pub unsafe fn from_libusb(
205        context: T,
206        handle: NonNull<libusb_device_handle>,
207    ) -> DeviceHandle<T> {
208        DeviceHandle {
209            context,
210            handle: Some(handle),
211            interfaces: Mutex::new(ClaimedInterfaces::new()),
212        }
213    }
214
215    /// Returns the active configuration number.
216    pub fn active_configuration(&self) -> crate::Result<u8> {
217        let mut config = mem::MaybeUninit::<c_int>::uninit();
218
219        try_unsafe!(libusb_get_configuration(self.as_raw(), config.as_mut_ptr()));
220        Ok(unsafe { config.assume_init() } as u8)
221    }
222
223    /// Sets the device's active configuration.
224    pub fn set_active_configuration(&self, config: u8) -> crate::Result<()> {
225        try_unsafe!(libusb_set_configuration(self.as_raw(), c_int::from(config)));
226        Ok(())
227    }
228
229    /// Puts the device in an unconfigured state.
230    pub fn unconfigure(&self) -> crate::Result<()> {
231        try_unsafe!(libusb_set_configuration(self.as_raw(), -1));
232        Ok(())
233    }
234
235    /// Resets the device.
236    pub fn reset(&self) -> crate::Result<()> {
237        try_unsafe!(libusb_reset_device(self.as_raw()));
238        Ok(())
239    }
240
241    /// Clear the halt/stall condition for an endpoint.
242    pub fn clear_halt(&self, endpoint: u8) -> crate::Result<()> {
243        try_unsafe!(libusb_clear_halt(self.as_raw(), endpoint));
244        Ok(())
245    }
246
247    /// Indicates whether the device has an attached kernel driver.
248    ///
249    /// This method is not supported on all platforms.
250    pub fn kernel_driver_active(&self, iface: u8) -> crate::Result<bool> {
251        match unsafe { libusb_kernel_driver_active(self.as_raw(), c_int::from(iface)) } {
252            0 => Ok(false),
253            1 => Ok(true),
254            err => Err(error::from_libusb(err)),
255        }
256    }
257
258    /// Detaches an attached kernel driver from the device.
259    ///
260    /// This method is not supported on all platforms.
261    pub fn detach_kernel_driver(&self, iface: u8) -> crate::Result<()> {
262        try_unsafe!(libusb_detach_kernel_driver(
263            self.as_raw(),
264            c_int::from(iface)
265        ));
266        Ok(())
267    }
268
269    /// Attaches a kernel driver to the device.
270    ///
271    /// This method is not supported on all platforms.
272    pub fn attach_kernel_driver(&self, iface: u8) -> crate::Result<()> {
273        try_unsafe!(libusb_attach_kernel_driver(
274            self.as_raw(),
275            c_int::from(iface)
276        ));
277        Ok(())
278    }
279
280    /// Enable/disable automatic kernel driver detachment.
281    ///
282    /// When this is enabled rusb will automatically detach the
283    /// kernel driver on an interface when claiming the interface, and
284    /// attach it when releasing the interface.
285    ///
286    /// On platforms which do not have support, this function will
287    /// return `Error::NotSupported`, and rusb will continue as if
288    /// this function was never called.
289    pub fn set_auto_detach_kernel_driver(&self, auto_detach: bool) -> crate::Result<()> {
290        try_unsafe!(libusb_set_auto_detach_kernel_driver(
291            self.as_raw(),
292            auto_detach.into()
293        ));
294        Ok(())
295    }
296
297    /// Claims one of the device's interfaces.
298    ///
299    /// An interface must be claimed before operating on it. All claimed interfaces are released
300    /// when the device handle goes out of scope.
301    pub fn claim_interface(&self, iface: u8) -> crate::Result<()> {
302        try_unsafe!(libusb_claim_interface(self.as_raw(), c_int::from(iface)));
303        self.interfaces.lock().unwrap().insert(iface);
304        Ok(())
305    }
306
307    /// Releases a claimed interface.
308    pub fn release_interface(&self, iface: u8) -> crate::Result<()> {
309        try_unsafe!(libusb_release_interface(self.as_raw(), c_int::from(iface)));
310        self.interfaces.lock().unwrap().remove(iface);
311        Ok(())
312    }
313
314    /// Sets an interface's active setting.
315    pub fn set_alternate_setting(&self, iface: u8, setting: u8) -> crate::Result<()> {
316        try_unsafe!(libusb_set_interface_alt_setting(
317            self.as_raw(),
318            c_int::from(iface),
319            c_int::from(setting)
320        ));
321        Ok(())
322    }
323
324    /// Reads from an interrupt endpoint.
325    ///
326    /// This function attempts to read from the interrupt endpoint with the address given by the
327    /// `endpoint` parameter and fills `buf` with any data received from the endpoint. The function
328    /// blocks up to the amount of time specified by `timeout`. Minimal `timeout` is 1 milliseconds,
329    /// anything smaller will result in an infinite block.
330    ///
331    /// If the return value is `Ok(n)`, then `buf` is populated with `n` bytes of data received
332    /// from the endpoint.
333    ///
334    /// ## Errors
335    ///
336    /// If this function encounters any form of error while fulfilling the transfer request, an
337    /// error variant will be returned. If an error variant is returned, no bytes were read.
338    ///
339    /// The errors returned by this function include:
340    ///
341    /// * `InvalidParam` if the endpoint is not an input endpoint.
342    /// * `Timeout` if the transfer timed out.
343    /// * `Pipe` if the endpoint halted.
344    /// * `Overflow` if the device offered more data.
345    /// * `NoDevice` if the device has been disconnected.
346    /// * `Io` if the transfer encountered an I/O error.
347    pub fn read_interrupt(
348        &self,
349        endpoint: u8,
350        buf: &mut [u8],
351        timeout: Duration,
352    ) -> crate::Result<usize> {
353        if endpoint & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_IN {
354            return Err(Error::InvalidParam);
355        }
356        let mut transferred = mem::MaybeUninit::<c_int>::uninit();
357        unsafe {
358            match libusb_interrupt_transfer(
359                self.as_raw(),
360                endpoint,
361                buf.as_mut_ptr() as *mut c_uchar,
362                buf.len() as c_int,
363                transferred.as_mut_ptr(),
364                timeout.as_millis() as c_uint,
365            ) {
366                0 => Ok(transferred.assume_init() as usize),
367                err if err == LIBUSB_ERROR_INTERRUPTED => {
368                    let transferred = transferred.assume_init();
369                    if transferred > 0 {
370                        Ok(transferred as usize)
371                    } else {
372                        Err(error::from_libusb(err))
373                    }
374                }
375                err => Err(error::from_libusb(err)),
376            }
377        }
378    }
379
380    /// Writes to an interrupt endpoint.
381    ///
382    /// This function attempts to write the contents of `buf` to the interrupt endpoint with the
383    /// address given by the `endpoint` parameter. The function blocks up to the amount of time
384    /// specified by `timeout`. Minimal `timeout` is 1 milliseconds, anything smaller will
385    /// result in an infinite block.
386    ///
387    /// If the return value is `Ok(n)`, then `n` bytes of `buf` were written to the endpoint.
388    ///
389    /// ## Errors
390    ///
391    /// If this function encounters any form of error while fulfilling the transfer request, an
392    /// error variant will be returned. If an error variant is returned, no bytes were written.
393    ///
394    /// The errors returned by this function include:
395    ///
396    /// * `InvalidParam` if the endpoint is not an output endpoint.
397    /// * `Timeout` if the transfer timed out.
398    /// * `Pipe` if the endpoint halted.
399    /// * `NoDevice` if the device has been disconnected.
400    /// * `Io` if the transfer encountered an I/O error.
401    pub fn write_interrupt(
402        &self,
403        endpoint: u8,
404        buf: &[u8],
405        timeout: Duration,
406    ) -> crate::Result<usize> {
407        if endpoint & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_OUT {
408            return Err(Error::InvalidParam);
409        }
410        let mut transferred = mem::MaybeUninit::<c_int>::uninit();
411        unsafe {
412            match libusb_interrupt_transfer(
413                self.as_raw(),
414                endpoint,
415                buf.as_ptr() as *mut c_uchar,
416                buf.len() as c_int,
417                transferred.as_mut_ptr(),
418                timeout.as_millis() as c_uint,
419            ) {
420                0 => Ok(transferred.assume_init() as usize),
421                err if err == LIBUSB_ERROR_INTERRUPTED => {
422                    let transferred = transferred.assume_init();
423                    if transferred > 0 {
424                        Ok(transferred as usize)
425                    } else {
426                        Err(error::from_libusb(err))
427                    }
428                }
429                err => Err(error::from_libusb(err)),
430            }
431        }
432    }
433
434    /// Reads from a bulk endpoint.
435    ///
436    /// This function attempts to read from the bulk endpoint with the address given by the
437    /// `endpoint` parameter and fills `buf` with any data received from the endpoint. The function
438    /// blocks up to the amount of time specified by `timeout`. Minimal `timeout` is 1 milliseconds,
439    /// anything smaller will result in an infinite block.
440    ///
441    /// If the return value is `Ok(n)`, then `buf` is populated with `n` bytes of data received
442    /// from the endpoint.
443    ///
444    /// ## Errors
445    ///
446    /// If this function encounters any form of error while fulfilling the transfer request, an
447    /// error variant will be returned. If an error variant is returned, no bytes were read.
448    ///
449    /// The errors returned by this function include:
450    ///
451    /// * `InvalidParam` if the endpoint is not an input endpoint.
452    /// * `Timeout` if the transfer timed out.
453    /// * `Pipe` if the endpoint halted.
454    /// * `Overflow` if the device offered more data.
455    /// * `NoDevice` if the device has been disconnected.
456    /// * `Io` if the transfer encountered an I/O error.
457    pub fn read_bulk(
458        &self,
459        endpoint: u8,
460        buf: &mut [u8],
461        timeout: Duration,
462    ) -> crate::Result<usize> {
463        if endpoint & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_IN {
464            return Err(Error::InvalidParam);
465        }
466        let mut transferred = mem::MaybeUninit::<c_int>::uninit();
467        unsafe {
468            match libusb_bulk_transfer(
469                self.as_raw(),
470                endpoint,
471                buf.as_mut_ptr() as *mut c_uchar,
472                buf.len() as c_int,
473                transferred.as_mut_ptr(),
474                timeout.as_millis() as c_uint,
475            ) {
476                0 => Ok(transferred.assume_init() as usize),
477                err if err == LIBUSB_ERROR_INTERRUPTED || err == LIBUSB_ERROR_TIMEOUT => {
478                    let transferred = transferred.assume_init();
479                    if transferred > 0 {
480                        Ok(transferred as usize)
481                    } else {
482                        Err(error::from_libusb(err))
483                    }
484                }
485                err => Err(error::from_libusb(err)),
486            }
487        }
488    }
489
490    /// Writes to a bulk endpoint.
491    ///
492    /// This function attempts to write the contents of `buf` to the bulk endpoint with the address
493    /// given by the `endpoint` parameter. The function blocks up to the amount of time specified
494    /// by `timeout`. Minimal `timeout` is 1 milliseconds, anything smaller will result in an
495    /// infinite block.
496    ///
497    /// If the return value is `Ok(n)`, then `n` bytes of `buf` were written to the endpoint.
498    ///
499    /// ## Errors
500    ///
501    /// If this function encounters any form of error while fulfilling the transfer request, an
502    /// error variant will be returned. If an error variant is returned, no bytes were written.
503    ///
504    /// The errors returned by this function include:
505    ///
506    /// * `InvalidParam` if the endpoint is not an output endpoint.
507    /// * `Timeout` if the transfer timed out.
508    /// * `Pipe` if the endpoint halted.
509    /// * `NoDevice` if the device has been disconnected.
510    /// * `Io` if the transfer encountered an I/O error.
511    pub fn write_bulk(&self, endpoint: u8, buf: &[u8], timeout: Duration) -> crate::Result<usize> {
512        if endpoint & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_OUT {
513            return Err(Error::InvalidParam);
514        }
515        let mut transferred = mem::MaybeUninit::<c_int>::uninit();
516        unsafe {
517            match libusb_bulk_transfer(
518                self.as_raw(),
519                endpoint,
520                buf.as_ptr() as *mut c_uchar,
521                buf.len() as c_int,
522                transferred.as_mut_ptr(),
523                timeout.as_millis() as c_uint,
524            ) {
525                0 => Ok(transferred.assume_init() as usize),
526                err if err == LIBUSB_ERROR_INTERRUPTED || err == LIBUSB_ERROR_TIMEOUT => {
527                    let transferred = transferred.assume_init();
528                    if transferred > 0 {
529                        Ok(transferred as usize)
530                    } else {
531                        Err(error::from_libusb(err))
532                    }
533                }
534                err => Err(error::from_libusb(err)),
535            }
536        }
537    }
538
539    /// Reads data using a control transfer.
540    ///
541    /// This function attempts to read data from the device using a control transfer and fills
542    /// `buf` with any data received during the transfer. The function blocks up to the amount of
543    /// time specified by `timeout`. Minimal `timeout` is 1 milliseconds, anything smaller will
544    /// result in an infinite block.
545    ///
546    /// The parameters `request_type`, `request`, `value`, and `index` specify the fields of the
547    /// control transfer setup packet (`bmRequestType`, `bRequest`, `wValue`, and `wIndex`
548    /// respectively). The values for each of these parameters shall be given in host-endian byte
549    /// order. The value for the `request_type` parameter can be built with the helper function,
550    /// [request_type()](fn.request_type.html). The meaning of the other parameters depends on the
551    /// type of control request.
552    ///
553    /// If the return value is `Ok(n)`, then `buf` is populated with `n` bytes of data.
554    ///
555    /// ## Errors
556    ///
557    /// If this function encounters any form of error while fulfilling the transfer request, an
558    /// error variant will be returned. If an error variant is returned, no bytes were read.
559    ///
560    /// The errors returned by this function include:
561    ///
562    /// * `InvalidParam` if `request_type` does not specify a read transfer.
563    /// * `Timeout` if the transfer timed out.
564    /// * `Pipe` if the control request was not supported by the device.
565    /// * `NoDevice` if the device has been disconnected.
566    /// * `Io` if the transfer encountered an I/O error.
567    pub fn read_control(
568        &self,
569        request_type: u8,
570        request: u8,
571        value: u16,
572        index: u16,
573        buf: &mut [u8],
574        timeout: Duration,
575    ) -> crate::Result<usize> {
576        if request_type & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_IN {
577            return Err(Error::InvalidParam);
578        }
579        let res = unsafe {
580            libusb_control_transfer(
581                self.as_raw(),
582                request_type,
583                request,
584                value,
585                index,
586                buf.as_mut_ptr() as *mut c_uchar,
587                buf.len() as u16,
588                timeout.as_millis() as c_uint,
589            )
590        };
591
592        if res < 0 {
593            Err(error::from_libusb(res))
594        } else {
595            Ok(res as usize)
596        }
597    }
598
599    /// Writes data using a control transfer.
600    ///
601    /// This function attempts to write the contents of `buf` to the device using a control
602    /// transfer. The function blocks up to the amount of time specified by `timeout`.
603    /// Minimal `timeout` is 1 milliseconds, anything smaller will result in an infinite block.
604    ///
605    /// The parameters `request_type`, `request`, `value`, and `index` specify the fields of the
606    /// control transfer setup packet (`bmRequestType`, `bRequest`, `wValue`, and `wIndex`
607    /// respectively). The values for each of these parameters shall be given in host-endian byte
608    /// order. The value for the `request_type` parameter can be built with the helper function,
609    /// [request_type()](fn.request_type.html). The meaning of the other parameters depends on the
610    /// type of control request.
611    ///
612    /// If the return value is `Ok(n)`, then `n` bytes of `buf` were transfered.
613    ///
614    /// ## Errors
615    ///
616    /// If this function encounters any form of error while fulfilling the transfer request, an
617    /// error variant will be returned. If an error variant is returned, no bytes were read.
618    ///
619    /// The errors returned by this function include:
620    ///
621    /// * `InvalidParam` if `request_type` does not specify a write transfer.
622    /// * `Timeout` if the transfer timed out.
623    /// * `Pipe` if the control request was not supported by the device.
624    /// * `NoDevice` if the device has been disconnected.
625    /// * `Io` if the transfer encountered an I/O error.
626    pub fn write_control(
627        &self,
628        request_type: u8,
629        request: u8,
630        value: u16,
631        index: u16,
632        buf: &[u8],
633        timeout: Duration,
634    ) -> crate::Result<usize> {
635        if request_type & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_OUT {
636            return Err(Error::InvalidParam);
637        }
638        let res = unsafe {
639            libusb_control_transfer(
640                self.as_raw(),
641                request_type,
642                request,
643                value,
644                index,
645                buf.as_ptr() as *mut c_uchar,
646                buf.len() as u16,
647                timeout.as_millis() as c_uint,
648            )
649        };
650
651        if res < 0 {
652            Err(error::from_libusb(res))
653        } else {
654            Ok(res as usize)
655        }
656    }
657
658    /// Reads the languages supported by the device's string descriptors.
659    ///
660    /// This function returns a list of languages that can be used to read the device's string
661    /// descriptors.
662    pub fn read_languages(&self, timeout: Duration) -> crate::Result<Vec<Language>> {
663        let mut buf = [0u8; 255];
664
665        let len = self.read_control(
666            request_type(Direction::In, RequestType::Standard, Recipient::Device),
667            LIBUSB_REQUEST_GET_DESCRIPTOR,
668            u16::from(LIBUSB_DT_STRING) << 8,
669            0,
670            &mut buf,
671            timeout,
672        )?;
673
674        if len < 2 || buf[0] != len as u8 || len & 0x01 != 0 {
675            return Err(Error::BadDescriptor);
676        }
677
678        if len == 2 {
679            return Ok(Vec::new());
680        }
681
682        Ok(buf[0..len]
683            .chunks(2)
684            .skip(1)
685            .map(|chunk| {
686                let lang_id = u16::from(chunk[0]) | u16::from(chunk[1]) << 8;
687                crate::language::from_lang_id(lang_id)
688            })
689            .collect())
690    }
691
692    /// Reads a ascii string descriptor from the device.
693    ///
694    pub fn read_string_descriptor_ascii(&self, index: u8) -> crate::Result<String> {
695        let mut buf = Vec::<u8>::with_capacity(255);
696
697        let ptr = buf.as_mut_ptr() as *mut c_uchar;
698        let capacity = buf.capacity() as i32;
699
700        let res =
701            unsafe { libusb_get_string_descriptor_ascii(self.as_raw(), index, ptr, capacity) };
702
703        if res < 0 {
704            return Err(error::from_libusb(res));
705        }
706
707        unsafe {
708            buf.set_len(res as usize);
709        }
710
711        String::from_utf8(buf).map_err(|_| Error::Other)
712    }
713
714    /// Reads a string descriptor from the device.
715    ///
716    /// `language` should be one of the languages returned from [`read_languages`](#method.read_languages).
717    pub fn read_string_descriptor(
718        &self,
719        language: Language,
720        index: u8,
721        timeout: Duration,
722    ) -> crate::Result<String> {
723        let mut buf = [0u16; 128];
724
725        let len = {
726            // SAFETY: since we create slice from existing slice pointer valid
727            // alignment of [u8] less or equal to the [u16]
728            // size is less then allocated buffer (128 * 2 = 256 => 256 < 255)
729            let buf = unsafe {
730                std::slice::from_raw_parts_mut(
731                    buf.as_mut_ptr().cast::<u8>(),
732                    255, // Some devices choke on size > 255
733                )
734            };
735
736            let len = self.read_control(
737                request_type(Direction::In, RequestType::Standard, Recipient::Device),
738                LIBUSB_REQUEST_GET_DESCRIPTOR,
739                u16::from(LIBUSB_DT_STRING) << 8 | u16::from(index),
740                language.lang_id(),
741                buf,
742                timeout,
743            )?;
744
745            if len < 2 || buf[0] != len as u8 || len & 0x01 != 0 {
746                return Err(Error::BadDescriptor);
747            }
748
749            len
750        };
751
752        if len == 2 {
753            return Ok(String::new());
754        }
755
756        // len in bytes, skip first element(it's contain descriptor type and len)
757        String::from_utf16(&buf[1..(len / 2)]).map_err(|_| Error::Other)
758    }
759
760    /// Reads the device's manufacturer string descriptor (ascii).
761    pub fn read_manufacturer_string_ascii(
762        &self,
763        device: &DeviceDescriptor,
764    ) -> crate::Result<String> {
765        match device.manufacturer_string_index() {
766            None => Err(Error::InvalidParam),
767            Some(n) => self.read_string_descriptor_ascii(n),
768        }
769    }
770
771    /// Reads the device's manufacturer string descriptor.
772    pub fn read_manufacturer_string(
773        &self,
774        language: Language,
775        device: &DeviceDescriptor,
776        timeout: Duration,
777    ) -> crate::Result<String> {
778        match device.manufacturer_string_index() {
779            None => Err(Error::InvalidParam),
780            Some(n) => self.read_string_descriptor(language, n, timeout),
781        }
782    }
783
784    /// Reads the device's product string descriptor (ascii).
785    pub fn read_product_string_ascii(&self, device: &DeviceDescriptor) -> crate::Result<String> {
786        match device.product_string_index() {
787            None => Err(Error::InvalidParam),
788            Some(n) => self.read_string_descriptor_ascii(n),
789        }
790    }
791
792    /// Reads the device's product string descriptor.
793    pub fn read_product_string(
794        &self,
795        language: Language,
796        device: &DeviceDescriptor,
797        timeout: Duration,
798    ) -> crate::Result<String> {
799        match device.product_string_index() {
800            None => Err(Error::InvalidParam),
801            Some(n) => self.read_string_descriptor(language, n, timeout),
802        }
803    }
804
805    /// Reads the device's serial number string descriptor (ascii).
806    pub fn read_serial_number_string_ascii(
807        &self,
808        device: &DeviceDescriptor,
809    ) -> crate::Result<String> {
810        match device.serial_number_string_index() {
811            None => Err(Error::InvalidParam),
812            Some(n) => self.read_string_descriptor_ascii(n),
813        }
814    }
815
816    /// Reads the device's serial number string descriptor.
817    pub fn read_serial_number_string(
818        &self,
819        language: Language,
820        device: &DeviceDescriptor,
821        timeout: Duration,
822    ) -> crate::Result<String> {
823        match device.serial_number_string_index() {
824            None => Err(Error::InvalidParam),
825            Some(n) => self.read_string_descriptor(language, n, timeout),
826        }
827    }
828
829    /// Reads the string descriptor for a configuration's description.
830    pub fn read_configuration_string(
831        &self,
832        language: Language,
833        configuration: &ConfigDescriptor,
834        timeout: Duration,
835    ) -> crate::Result<String> {
836        match configuration.description_string_index() {
837            None => Err(Error::InvalidParam),
838            Some(n) => self.read_string_descriptor(language, n, timeout),
839        }
840    }
841
842    /// Reads the string descriptor for a interface's description.
843    pub fn read_interface_string(
844        &self,
845        language: Language,
846        interface: &InterfaceDescriptor,
847        timeout: Duration,
848    ) -> crate::Result<String> {
849        match interface.description_string_index() {
850            None => Err(Error::InvalidParam),
851            Some(n) => self.read_string_descriptor(language, n, timeout),
852        }
853    }
854}
855
856#[cfg(test)]
857mod tests {
858    use super::ClaimedInterfaces;
859    use std::u8;
860
861    #[test]
862    fn claimed_interfaces_empty() {
863        let empty = ClaimedInterfaces::new();
864        assert_eq!(empty.size(), 0);
865        for i in 0..=u8::MAX {
866            assert!(!empty.contains(i), "empty set should not contain {}", i);
867        }
868
869        let mut iter = empty.iter();
870        assert_eq!(iter.size_hint(), (0, Some(0)));
871        assert_eq!(iter.next(), None);
872    }
873
874    #[test]
875    fn claimed_interfaces_one_element() {
876        let mut interfaces = ClaimedInterfaces::new();
877        interfaces.insert(94);
878        assert_eq!(interfaces.size(), 1);
879        assert!(interfaces.contains(94));
880        for i in 0..=u8::MAX {
881            if i == 94 {
882                continue;
883            }
884            assert!(
885                !interfaces.contains(i),
886                "interfaces should not contain {}",
887                i
888            );
889        }
890
891        let mut iter = interfaces.iter();
892        assert_eq!(iter.size_hint(), (1, Some(1)));
893        assert_eq!(iter.next(), Some(94));
894        assert_eq!(iter.size_hint(), (0, Some(0)));
895        assert_eq!(iter.next(), None);
896    }
897
898    #[test]
899    fn claimed_interfaces_many_elements() {
900        let mut interfaces = ClaimedInterfaces::new();
901        let elements = vec![94, 0, 255, 17, 183, 6];
902
903        for (index, &interface) in elements.iter().enumerate() {
904            interfaces.insert(interface);
905            assert_eq!(interfaces.size(), index + 1);
906        }
907
908        // Validate contains().
909        for &interface in elements.iter() {
910            assert!(
911                interfaces.contains(interface),
912                "interfaces should contain {}",
913                interface
914            );
915        }
916
917        // Validate iter().
918        let contents = interfaces.iter().collect::<Vec<_>>().sort();
919        assert_eq!(contents, elements.clone().sort());
920
921        // Validate size_hint().
922        let mut iter = interfaces.iter();
923        let mut read = 0;
924        loop {
925            assert!(
926                read <= elements.len(),
927                "read elements {} should not exceed elements size {}",
928                read,
929                elements.len()
930            );
931            let remaining = elements.len() - read;
932            assert_eq!(iter.size_hint(), (remaining, Some(remaining)));
933            match iter.next() {
934                Some(_) => read += 1,
935                None => break,
936            }
937        }
938    }
939}