1use libmtp_sys as ffi;
5use std::ffi::CStr;
6use std::fmt::{self, Debug};
7use std::mem::MaybeUninit;
8
9use crate::device::MtpDevice;
10use crate::error::{Error, MtpErrorKind};
11use crate::internals::{maybe_init, DeviceEntry};
12use crate::Result;
13
14pub struct RawDevice {
17 pub(crate) inner: ffi::LIBMTP_raw_device_struct,
18}
19
20impl Debug for RawDevice {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 f.debug_struct("RawDevice")
23 .field("bus_number", &self.bus_number())
24 .field("dev_number", &self.dev_number())
25 .field("device_entry", &self.device_entry())
26 .finish()
27 }
28}
29
30impl RawDevice {
31 pub fn open(&self) -> Option<MtpDevice> {
34 unsafe {
35 let ptr = &self.inner as *const _;
36 let device = ffi::LIBMTP_Open_Raw_Device(ptr as *mut _);
37
38 if device.is_null() {
39 None
40 } else {
41 Some(MtpDevice { inner: device })
42 }
43 }
44 }
45
46 pub fn open_uncached(&self) -> Option<MtpDevice> {
48 unsafe {
49 let ptr = &self.inner as *const _;
50 let device = ffi::LIBMTP_Open_Raw_Device_Uncached(ptr as *mut _);
51
52 if device.is_null() {
53 None
54 } else {
55 Some(MtpDevice { inner: device })
56 }
57 }
58 }
59
60 pub fn bus_number(&self) -> u32 {
62 self.inner.bus_location
63 }
64
65 pub fn dev_number(&self) -> u8 {
67 self.inner.devnum
68 }
69
70 pub fn device_entry(&self) -> DeviceEntry {
72 let vendor;
73 let product;
74
75 unsafe {
76 vendor = CStr::from_ptr(self.inner.device_entry.vendor);
77 product = CStr::from_ptr(self.inner.device_entry.product);
78 }
79
80 DeviceEntry {
81 vendor: vendor.to_str().expect("Invalid UTF-8 in music-players.h?"),
82 vendor_id: self.inner.device_entry.vendor_id,
83 product: product.to_str().expect("Invalid UTF-8 in music-players.h?"),
84 product_id: self.inner.device_entry.product_id,
85 device_flags: self.inner.device_entry.device_flags,
86 }
87 }
88}
89
90pub fn detect_raw_devices() -> Result<Vec<RawDevice>> {
108 maybe_init();
109
110 unsafe {
111 let mut devices = std::ptr::null_mut();
112 let mut len = 0;
113
114 let res = ffi::LIBMTP_Detect_Raw_Devices(&mut devices, &mut len);
115
116 if let Some(kind) = MtpErrorKind::from_error_number(res) {
117 Err(Error::MtpError {
118 kind,
119 text: "Failed to detect raw devices".to_string(),
120 })
121 } else {
122 let mut devices_vec = Vec::with_capacity(len as usize);
123 for i in 0..(len as isize) {
124 let mut new = MaybeUninit::zeroed().assume_init();
125
126 std::ptr::copy_nonoverlapping(devices.offset(i), &mut new, 1);
127 devices_vec.push(RawDevice { inner: new });
128 }
129
130 libc::free(devices as *mut _);
131 Ok(devices_vec)
132 }
133 }
134}
135
136pub fn check_specific_device(bus_number: u32, dev_number: u32) -> bool {
139 let res = unsafe { ffi::LIBMTP_Check_Specific_Device(bus_number as i32, dev_number as i32) };
140 res == 1
141}