1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::convert::TryInto; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File; 7*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Read; 8*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Seek; 9*bb4ee6a4SAndroid Build Coastguard Worker use std::io::SeekFrom; 10*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of_val; 11*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_int; 12*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_uchar; 13*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_uint; 14*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_void; 15*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc; 16*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Weak; 17*bb4ee6a4SAndroid Build Coastguard Worker 18*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 19*bb4ee6a4SAndroid Build Coastguard Worker use base::handle_eintr_errno; 20*bb4ee6a4SAndroid Build Coastguard Worker use base::warn; 21*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor; 22*bb4ee6a4SAndroid Build Coastguard Worker use base::IoctlNr; 23*bb4ee6a4SAndroid Build Coastguard Worker use base::MappedRegion; 24*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMapping; 25*bb4ee6a4SAndroid Build Coastguard Worker use base::MemoryMappingBuilder; 26*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection; 27*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor; 28*bb4ee6a4SAndroid Build Coastguard Worker use data_model::vec_with_array_field; 29*bb4ee6a4SAndroid Build Coastguard Worker use libc::EAGAIN; 30*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENODEV; 31*bb4ee6a4SAndroid Build Coastguard Worker use libc::ENOENT; 32*bb4ee6a4SAndroid Build Coastguard Worker use libc::EPIPE; 33*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex; 34*bb4ee6a4SAndroid Build Coastguard Worker 35*bb4ee6a4SAndroid Build Coastguard Worker use crate::control_request_type; 36*bb4ee6a4SAndroid Build Coastguard Worker use crate::descriptor; 37*bb4ee6a4SAndroid Build Coastguard Worker use crate::ConfigDescriptorTree; 38*bb4ee6a4SAndroid Build Coastguard Worker use crate::ControlRequestDataPhaseTransferDirection; 39*bb4ee6a4SAndroid Build Coastguard Worker use crate::ControlRequestRecipient; 40*bb4ee6a4SAndroid Build Coastguard Worker use crate::ControlRequestType; 41*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceDescriptor; 42*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceDescriptorTree; 43*bb4ee6a4SAndroid Build Coastguard Worker use crate::DeviceSpeed; 44*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error; 45*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result; 46*bb4ee6a4SAndroid Build Coastguard Worker use crate::StandardControlRequest; 47*bb4ee6a4SAndroid Build Coastguard Worker 48*bb4ee6a4SAndroid Build Coastguard Worker // This is the maximum block size observed during storage performance test 49*bb4ee6a4SAndroid Build Coastguard Worker const MMAP_SIZE: usize = 1024 * 1024; 50*bb4ee6a4SAndroid Build Coastguard Worker 51*bb4ee6a4SAndroid Build Coastguard Worker /// ManagedDmaBuffer represents the entire DMA buffer allocated by a device 52*bb4ee6a4SAndroid Build Coastguard Worker struct ManagedDmaBuffer { 53*bb4ee6a4SAndroid Build Coastguard Worker /// The entire DMA buffer 54*bb4ee6a4SAndroid Build Coastguard Worker buf: MemoryMapping, 55*bb4ee6a4SAndroid Build Coastguard Worker /// A DMA buffer lent to a TransferBuffer. This is a part of the entire buffer. 56*bb4ee6a4SAndroid Build Coastguard Worker used: Option<Arc<Mutex<DmaBuffer>>>, 57*bb4ee6a4SAndroid Build Coastguard Worker } 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard Worker /// DmaBuffer represents a DMA buffer lent by a device 60*bb4ee6a4SAndroid Build Coastguard Worker pub struct DmaBuffer { 61*bb4ee6a4SAndroid Build Coastguard Worker /// Host virtual address of the buffer 62*bb4ee6a4SAndroid Build Coastguard Worker addr: u64, 63*bb4ee6a4SAndroid Build Coastguard Worker /// Size of the buffer 64*bb4ee6a4SAndroid Build Coastguard Worker size: usize, 65*bb4ee6a4SAndroid Build Coastguard Worker } 66*bb4ee6a4SAndroid Build Coastguard Worker 67*bb4ee6a4SAndroid Build Coastguard Worker impl DmaBuffer { address(&mut self) -> *mut c_void68*bb4ee6a4SAndroid Build Coastguard Worker pub fn address(&mut self) -> *mut c_void { 69*bb4ee6a4SAndroid Build Coastguard Worker self.addr as *mut c_void 70*bb4ee6a4SAndroid Build Coastguard Worker } 71*bb4ee6a4SAndroid Build Coastguard Worker size(&self) -> usize72*bb4ee6a4SAndroid Build Coastguard Worker pub fn size(&self) -> usize { 73*bb4ee6a4SAndroid Build Coastguard Worker self.size 74*bb4ee6a4SAndroid Build Coastguard Worker } 75*bb4ee6a4SAndroid Build Coastguard Worker as_slice(&self) -> &[u8]76*bb4ee6a4SAndroid Build Coastguard Worker pub fn as_slice(&self) -> &[u8] { 77*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 78*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the region has been lent by a device 79*bb4ee6a4SAndroid Build Coastguard Worker unsafe { std::slice::from_raw_parts(self.addr as *const u8, self.size) } 80*bb4ee6a4SAndroid Build Coastguard Worker } 81*bb4ee6a4SAndroid Build Coastguard Worker as_mut_slice(&mut self) -> &mut [u8]82*bb4ee6a4SAndroid Build Coastguard Worker pub fn as_mut_slice(&mut self) -> &mut [u8] { 83*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 84*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the region has been lent by a device 85*bb4ee6a4SAndroid Build Coastguard Worker unsafe { std::slice::from_raw_parts_mut(self.addr as *mut u8, self.size) } 86*bb4ee6a4SAndroid Build Coastguard Worker } 87*bb4ee6a4SAndroid Build Coastguard Worker } 88*bb4ee6a4SAndroid Build Coastguard Worker 89*bb4ee6a4SAndroid Build Coastguard Worker /// TransferBuffer is used for data transfer between crosvm and the host kernel 90*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone)] 91*bb4ee6a4SAndroid Build Coastguard Worker pub enum TransferBuffer { 92*bb4ee6a4SAndroid Build Coastguard Worker Vector(Vec<u8>), 93*bb4ee6a4SAndroid Build Coastguard Worker Dma(Weak<Mutex<DmaBuffer>>), 94*bb4ee6a4SAndroid Build Coastguard Worker } 95*bb4ee6a4SAndroid Build Coastguard Worker 96*bb4ee6a4SAndroid Build Coastguard Worker impl TransferBuffer { address(&mut self) -> Option<*mut c_void>97*bb4ee6a4SAndroid Build Coastguard Worker pub fn address(&mut self) -> Option<*mut c_void> { 98*bb4ee6a4SAndroid Build Coastguard Worker match self { 99*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Vector(v) => Some(v.as_mut_ptr() as *mut c_void), 100*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Dma(buf) => buf.upgrade().map(|buf| buf.lock().address()), 101*bb4ee6a4SAndroid Build Coastguard Worker } 102*bb4ee6a4SAndroid Build Coastguard Worker } size(&self) -> Option<usize>103*bb4ee6a4SAndroid Build Coastguard Worker pub fn size(&self) -> Option<usize> { 104*bb4ee6a4SAndroid Build Coastguard Worker match self { 105*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Vector(v) => Some(v.len()), 106*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Dma(buf) => buf.upgrade().map(|buf| buf.lock().size()), 107*bb4ee6a4SAndroid Build Coastguard Worker } 108*bb4ee6a4SAndroid Build Coastguard Worker } 109*bb4ee6a4SAndroid Build Coastguard Worker } 110*bb4ee6a4SAndroid Build Coastguard Worker 111*bb4ee6a4SAndroid Build Coastguard Worker /// Device represents a USB device. 112*bb4ee6a4SAndroid Build Coastguard Worker pub struct Device { 113*bb4ee6a4SAndroid Build Coastguard Worker fd: Arc<File>, 114*bb4ee6a4SAndroid Build Coastguard Worker device_descriptor_tree: DeviceDescriptorTree, 115*bb4ee6a4SAndroid Build Coastguard Worker dma_buffer: Option<ManagedDmaBuffer>, 116*bb4ee6a4SAndroid Build Coastguard Worker } 117*bb4ee6a4SAndroid Build Coastguard Worker 118*bb4ee6a4SAndroid Build Coastguard Worker /// Transfer contains the information necessary to submit a USB request 119*bb4ee6a4SAndroid Build Coastguard Worker /// and, once it has been submitted and completed, contains the response. 120*bb4ee6a4SAndroid Build Coastguard Worker pub struct Transfer { 121*bb4ee6a4SAndroid Build Coastguard Worker // NOTE: This Vec is actually a single URB with a trailing 122*bb4ee6a4SAndroid Build Coastguard Worker // variable-length field created by vec_with_array_field(). 123*bb4ee6a4SAndroid Build Coastguard Worker urb: Vec<usb_sys::usbdevfs_urb>, 124*bb4ee6a4SAndroid Build Coastguard Worker pub buffer: TransferBuffer, 125*bb4ee6a4SAndroid Build Coastguard Worker callback: Option<Box<dyn Fn(Transfer) + Send + Sync>>, 126*bb4ee6a4SAndroid Build Coastguard Worker } 127*bb4ee6a4SAndroid Build Coastguard Worker 128*bb4ee6a4SAndroid Build Coastguard Worker /// TransferHandle is a handle that allows cancellation of in-flight transfers 129*bb4ee6a4SAndroid Build Coastguard Worker /// between submit_transfer() and get_completed_transfer(). 130*bb4ee6a4SAndroid Build Coastguard Worker /// Attempting to cancel a transfer that has already completed is safe and will 131*bb4ee6a4SAndroid Build Coastguard Worker /// return an error. 132*bb4ee6a4SAndroid Build Coastguard Worker pub struct TransferHandle { 133*bb4ee6a4SAndroid Build Coastguard Worker weak_transfer: std::sync::Weak<Transfer>, 134*bb4ee6a4SAndroid Build Coastguard Worker fd: std::sync::Weak<File>, 135*bb4ee6a4SAndroid Build Coastguard Worker } 136*bb4ee6a4SAndroid Build Coastguard Worker 137*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Eq, Clone, Copy)] 138*bb4ee6a4SAndroid Build Coastguard Worker pub enum TransferStatus { 139*bb4ee6a4SAndroid Build Coastguard Worker Completed, 140*bb4ee6a4SAndroid Build Coastguard Worker Error, 141*bb4ee6a4SAndroid Build Coastguard Worker Cancelled, 142*bb4ee6a4SAndroid Build Coastguard Worker NoDevice, 143*bb4ee6a4SAndroid Build Coastguard Worker Stalled, 144*bb4ee6a4SAndroid Build Coastguard Worker } 145*bb4ee6a4SAndroid Build Coastguard Worker 146*bb4ee6a4SAndroid Build Coastguard Worker impl Device { 147*bb4ee6a4SAndroid Build Coastguard Worker /// Create a new `Device` from a file descriptor. 148*bb4ee6a4SAndroid Build Coastguard Worker /// `fd` should be a file in usbdevfs (e.g. `/dev/bus/usb/001/002`). new(mut fd: File) -> Result<Self>149*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(mut fd: File) -> Result<Self> { 150*bb4ee6a4SAndroid Build Coastguard Worker fd.seek(SeekFrom::Start(0)).map_err(Error::DescriptorRead)?; 151*bb4ee6a4SAndroid Build Coastguard Worker let mut descriptor_data = Vec::new(); 152*bb4ee6a4SAndroid Build Coastguard Worker fd.read_to_end(&mut descriptor_data) 153*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::DescriptorRead)?; 154*bb4ee6a4SAndroid Build Coastguard Worker let device_descriptor_tree = descriptor::parse_usbfs_descriptors(&descriptor_data)?; 155*bb4ee6a4SAndroid Build Coastguard Worker 156*bb4ee6a4SAndroid Build Coastguard Worker let mut device = Device { 157*bb4ee6a4SAndroid Build Coastguard Worker fd: Arc::new(fd), 158*bb4ee6a4SAndroid Build Coastguard Worker device_descriptor_tree, 159*bb4ee6a4SAndroid Build Coastguard Worker dma_buffer: None, 160*bb4ee6a4SAndroid Build Coastguard Worker }; 161*bb4ee6a4SAndroid Build Coastguard Worker 162*bb4ee6a4SAndroid Build Coastguard Worker let map = MemoryMappingBuilder::new(MMAP_SIZE) 163*bb4ee6a4SAndroid Build Coastguard Worker .from_file(&device.fd) 164*bb4ee6a4SAndroid Build Coastguard Worker .protection(Protection::read_write()) 165*bb4ee6a4SAndroid Build Coastguard Worker .build(); 166*bb4ee6a4SAndroid Build Coastguard Worker match map { 167*bb4ee6a4SAndroid Build Coastguard Worker Ok(map) => { 168*bb4ee6a4SAndroid Build Coastguard Worker device.dma_buffer = Some(ManagedDmaBuffer { 169*bb4ee6a4SAndroid Build Coastguard Worker buf: map, 170*bb4ee6a4SAndroid Build Coastguard Worker used: None, 171*bb4ee6a4SAndroid Build Coastguard Worker }); 172*bb4ee6a4SAndroid Build Coastguard Worker } 173*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => { 174*bb4ee6a4SAndroid Build Coastguard Worker // Ignore the error since we can process requests without DMA buffer 175*bb4ee6a4SAndroid Build Coastguard Worker warn!( 176*bb4ee6a4SAndroid Build Coastguard Worker "mmap() failed. User-provided buffer will be used for data transfer. {}", 177*bb4ee6a4SAndroid Build Coastguard Worker e 178*bb4ee6a4SAndroid Build Coastguard Worker ); 179*bb4ee6a4SAndroid Build Coastguard Worker } 180*bb4ee6a4SAndroid Build Coastguard Worker } 181*bb4ee6a4SAndroid Build Coastguard Worker Ok(device) 182*bb4ee6a4SAndroid Build Coastguard Worker } 183*bb4ee6a4SAndroid Build Coastguard Worker fd(&self) -> Arc<File>184*bb4ee6a4SAndroid Build Coastguard Worker pub fn fd(&self) -> Arc<File> { 185*bb4ee6a4SAndroid Build Coastguard Worker self.fd.clone() 186*bb4ee6a4SAndroid Build Coastguard Worker } 187*bb4ee6a4SAndroid Build Coastguard Worker ioctl(&self, nr: IoctlNr) -> Result<i32>188*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn ioctl(&self, nr: IoctlNr) -> Result<i32> { 189*bb4ee6a4SAndroid Build Coastguard Worker let ret = handle_eintr_errno!(base::ioctl(&*self.fd, nr)); 190*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 191*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::IoctlFailed(nr, base::Error::last())); 192*bb4ee6a4SAndroid Build Coastguard Worker } 193*bb4ee6a4SAndroid Build Coastguard Worker Ok(ret) 194*bb4ee6a4SAndroid Build Coastguard Worker } 195*bb4ee6a4SAndroid Build Coastguard Worker ioctl_with_ref<T>(&self, nr: IoctlNr, arg: &T) -> Result<i32>196*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn ioctl_with_ref<T>(&self, nr: IoctlNr, arg: &T) -> Result<i32> { 197*bb4ee6a4SAndroid Build Coastguard Worker let ret = handle_eintr_errno!(base::ioctl_with_ref(&*self.fd, nr, arg)); 198*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 199*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::IoctlFailed(nr, base::Error::last())); 200*bb4ee6a4SAndroid Build Coastguard Worker } 201*bb4ee6a4SAndroid Build Coastguard Worker Ok(ret) 202*bb4ee6a4SAndroid Build Coastguard Worker } 203*bb4ee6a4SAndroid Build Coastguard Worker ioctl_with_mut_ref<T>(&self, nr: IoctlNr, arg: &mut T) -> Result<i32>204*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn ioctl_with_mut_ref<T>(&self, nr: IoctlNr, arg: &mut T) -> Result<i32> { 205*bb4ee6a4SAndroid Build Coastguard Worker let ret = handle_eintr_errno!(base::ioctl_with_mut_ref(&*self.fd, nr, arg)); 206*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 207*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::IoctlFailed(nr, base::Error::last())); 208*bb4ee6a4SAndroid Build Coastguard Worker } 209*bb4ee6a4SAndroid Build Coastguard Worker Ok(ret) 210*bb4ee6a4SAndroid Build Coastguard Worker } 211*bb4ee6a4SAndroid Build Coastguard Worker ioctl_with_mut_ptr<T>(&self, nr: IoctlNr, arg: *mut T) -> Result<i32>212*bb4ee6a4SAndroid Build Coastguard Worker unsafe fn ioctl_with_mut_ptr<T>(&self, nr: IoctlNr, arg: *mut T) -> Result<i32> { 213*bb4ee6a4SAndroid Build Coastguard Worker let ret = handle_eintr_errno!(base::ioctl_with_mut_ptr(&*self.fd, nr, arg)); 214*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 { 215*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::IoctlFailed(nr, base::Error::last())); 216*bb4ee6a4SAndroid Build Coastguard Worker } 217*bb4ee6a4SAndroid Build Coastguard Worker Ok(ret) 218*bb4ee6a4SAndroid Build Coastguard Worker } 219*bb4ee6a4SAndroid Build Coastguard Worker reserve_dma_buffer(&mut self, size: usize) -> Result<Weak<Mutex<DmaBuffer>>>220*bb4ee6a4SAndroid Build Coastguard Worker pub fn reserve_dma_buffer(&mut self, size: usize) -> Result<Weak<Mutex<DmaBuffer>>> { 221*bb4ee6a4SAndroid Build Coastguard Worker if let Some(managed) = &mut self.dma_buffer { 222*bb4ee6a4SAndroid Build Coastguard Worker if managed.used.is_none() { 223*bb4ee6a4SAndroid Build Coastguard Worker let buf = Arc::new(Mutex::new(DmaBuffer { 224*bb4ee6a4SAndroid Build Coastguard Worker addr: managed.buf.as_ptr() as u64, 225*bb4ee6a4SAndroid Build Coastguard Worker size, 226*bb4ee6a4SAndroid Build Coastguard Worker })); 227*bb4ee6a4SAndroid Build Coastguard Worker let ret = Ok(Arc::downgrade(&buf)); 228*bb4ee6a4SAndroid Build Coastguard Worker managed.used = Some(buf); 229*bb4ee6a4SAndroid Build Coastguard Worker return ret; 230*bb4ee6a4SAndroid Build Coastguard Worker } 231*bb4ee6a4SAndroid Build Coastguard Worker } 232*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::GetDmaBufferFailed(size)) 233*bb4ee6a4SAndroid Build Coastguard Worker } 234*bb4ee6a4SAndroid Build Coastguard Worker release_dma_buffer(&mut self, dmabuf: Weak<Mutex<DmaBuffer>>) -> Result<()>235*bb4ee6a4SAndroid Build Coastguard Worker pub fn release_dma_buffer(&mut self, dmabuf: Weak<Mutex<DmaBuffer>>) -> Result<()> { 236*bb4ee6a4SAndroid Build Coastguard Worker if let Some(managed) = &mut self.dma_buffer { 237*bb4ee6a4SAndroid Build Coastguard Worker if let Some(released) = dmabuf.upgrade() { 238*bb4ee6a4SAndroid Build Coastguard Worker let addr = { released.lock().address() as u64 }; 239*bb4ee6a4SAndroid Build Coastguard Worker if let Some(lent) = &managed.used { 240*bb4ee6a4SAndroid Build Coastguard Worker if lent.lock().addr == addr { 241*bb4ee6a4SAndroid Build Coastguard Worker managed.used = None; 242*bb4ee6a4SAndroid Build Coastguard Worker return Ok(()); 243*bb4ee6a4SAndroid Build Coastguard Worker } 244*bb4ee6a4SAndroid Build Coastguard Worker } 245*bb4ee6a4SAndroid Build Coastguard Worker } 246*bb4ee6a4SAndroid Build Coastguard Worker } 247*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::ReleaseDmaBufferFailed) 248*bb4ee6a4SAndroid Build Coastguard Worker } 249*bb4ee6a4SAndroid Build Coastguard Worker 250*bb4ee6a4SAndroid Build Coastguard Worker /// Submit a transfer to the device. 251*bb4ee6a4SAndroid Build Coastguard Worker /// The transfer will be processed asynchronously by the device. 252*bb4ee6a4SAndroid Build Coastguard Worker /// Call `poll_transfers()` on this device to check for completed transfers. submit_transfer(&mut self, transfer: Transfer) -> Result<TransferHandle>253*bb4ee6a4SAndroid Build Coastguard Worker pub fn submit_transfer(&mut self, transfer: Transfer) -> Result<TransferHandle> { 254*bb4ee6a4SAndroid Build Coastguard Worker let mut rc_transfer = Arc::new(transfer); 255*bb4ee6a4SAndroid Build Coastguard Worker 256*bb4ee6a4SAndroid Build Coastguard Worker // Technically, Arc::from_raw() should only be called on pointers returned 257*bb4ee6a4SAndroid Build Coastguard Worker // from Arc::into_raw(). However, we need to stash this value inside the 258*bb4ee6a4SAndroid Build Coastguard Worker // Arc<Transfer> itself, so we manually calculate the address that would be 259*bb4ee6a4SAndroid Build Coastguard Worker // returned from Arc::into_raw() via Deref and then call Arc::into_raw() 260*bb4ee6a4SAndroid Build Coastguard Worker // to forget the Arc without dropping its contents. 261*bb4ee6a4SAndroid Build Coastguard Worker // Do not remove the into_raw() call! 262*bb4ee6a4SAndroid Build Coastguard Worker let raw_transfer = (&*rc_transfer) as *const Transfer as usize; 263*bb4ee6a4SAndroid Build Coastguard Worker match Arc::get_mut(&mut rc_transfer) { 264*bb4ee6a4SAndroid Build Coastguard Worker Some(t) => t.urb_mut().usercontext = raw_transfer, 265*bb4ee6a4SAndroid Build Coastguard Worker None => { 266*bb4ee6a4SAndroid Build Coastguard Worker // This should never happen, since there is only one strong reference 267*bb4ee6a4SAndroid Build Coastguard Worker // at this point. 268*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::RcGetMutFailed); 269*bb4ee6a4SAndroid Build Coastguard Worker } 270*bb4ee6a4SAndroid Build Coastguard Worker } 271*bb4ee6a4SAndroid Build Coastguard Worker let _ = Arc::into_raw(rc_transfer.clone()); 272*bb4ee6a4SAndroid Build Coastguard Worker 273*bb4ee6a4SAndroid Build Coastguard Worker let urb_ptr = rc_transfer.urb.as_ptr() as *mut usb_sys::usbdevfs_urb; 274*bb4ee6a4SAndroid Build Coastguard Worker 275*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 276*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we control the lifetime of the URB via Arc::into_raw() and 277*bb4ee6a4SAndroid Build Coastguard Worker // Arc::from_raw() in poll_transfers(). 278*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 279*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_mut_ptr(usb_sys::USBDEVFS_SUBMITURB, urb_ptr)?; 280*bb4ee6a4SAndroid Build Coastguard Worker } 281*bb4ee6a4SAndroid Build Coastguard Worker 282*bb4ee6a4SAndroid Build Coastguard Worker let weak_transfer = Arc::downgrade(&rc_transfer); 283*bb4ee6a4SAndroid Build Coastguard Worker 284*bb4ee6a4SAndroid Build Coastguard Worker Ok(TransferHandle { 285*bb4ee6a4SAndroid Build Coastguard Worker weak_transfer, 286*bb4ee6a4SAndroid Build Coastguard Worker fd: Arc::downgrade(&self.fd), 287*bb4ee6a4SAndroid Build Coastguard Worker }) 288*bb4ee6a4SAndroid Build Coastguard Worker } 289*bb4ee6a4SAndroid Build Coastguard Worker 290*bb4ee6a4SAndroid Build Coastguard Worker /// Check for completed asynchronous transfers submitted via `submit_transfer()`. 291*bb4ee6a4SAndroid Build Coastguard Worker /// The callback for each completed transfer will be called. poll_transfers(&mut self) -> Result<()>292*bb4ee6a4SAndroid Build Coastguard Worker pub fn poll_transfers(&mut self) -> Result<()> { 293*bb4ee6a4SAndroid Build Coastguard Worker // Reap completed transfers until we get EAGAIN. 294*bb4ee6a4SAndroid Build Coastguard Worker loop { 295*bb4ee6a4SAndroid Build Coastguard Worker let mut urb_ptr: *mut usb_sys::usbdevfs_urb = std::ptr::null_mut(); 296*bb4ee6a4SAndroid Build Coastguard Worker let result = 297*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 298*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we provide a valid urb_ptr to be filled by the kernel. 299*bb4ee6a4SAndroid Build Coastguard Worker unsafe { self.ioctl_with_mut_ref(usb_sys::USBDEVFS_REAPURBNDELAY, &mut urb_ptr) }; 300*bb4ee6a4SAndroid Build Coastguard Worker match result { 301*bb4ee6a4SAndroid Build Coastguard Worker // EAGAIN indicates no more completed transfers right now. 302*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::IoctlFailed(_nr, e)) if e.errno() == EAGAIN => break, 303*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => return Err(e), 304*bb4ee6a4SAndroid Build Coastguard Worker Ok(_) => {} 305*bb4ee6a4SAndroid Build Coastguard Worker } 306*bb4ee6a4SAndroid Build Coastguard Worker 307*bb4ee6a4SAndroid Build Coastguard Worker if urb_ptr.is_null() { 308*bb4ee6a4SAndroid Build Coastguard Worker break; 309*bb4ee6a4SAndroid Build Coastguard Worker } 310*bb4ee6a4SAndroid Build Coastguard Worker 311*bb4ee6a4SAndroid Build Coastguard Worker let rc_transfer: Arc<Transfer> = 312*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 313*bb4ee6a4SAndroid Build Coastguard Worker // Safe because the URB usercontext field is always set to the result of 314*bb4ee6a4SAndroid Build Coastguard Worker // Arc::into_raw() in submit_transfer(). 315*bb4ee6a4SAndroid Build Coastguard Worker unsafe { Arc::from_raw((*urb_ptr).usercontext as *const Transfer) }; 316*bb4ee6a4SAndroid Build Coastguard Worker 317*bb4ee6a4SAndroid Build Coastguard Worker // There should always be exactly one strong reference to rc_transfer, 318*bb4ee6a4SAndroid Build Coastguard Worker // so try_unwrap() should never fail. 319*bb4ee6a4SAndroid Build Coastguard Worker let mut transfer = Arc::try_unwrap(rc_transfer).map_err(|_| Error::RcUnwrapFailed)?; 320*bb4ee6a4SAndroid Build Coastguard Worker 321*bb4ee6a4SAndroid Build Coastguard Worker let dmabuf = match &mut transfer.buffer { 322*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Dma(buf) => Some(buf.clone()), 323*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Vector(_) => None, 324*bb4ee6a4SAndroid Build Coastguard Worker }; 325*bb4ee6a4SAndroid Build Coastguard Worker 326*bb4ee6a4SAndroid Build Coastguard Worker if let Some(cb) = transfer.callback.take() { 327*bb4ee6a4SAndroid Build Coastguard Worker cb(transfer); 328*bb4ee6a4SAndroid Build Coastguard Worker } 329*bb4ee6a4SAndroid Build Coastguard Worker 330*bb4ee6a4SAndroid Build Coastguard Worker if let Some(dmabuf) = dmabuf { 331*bb4ee6a4SAndroid Build Coastguard Worker if self.release_dma_buffer(dmabuf).is_err() { 332*bb4ee6a4SAndroid Build Coastguard Worker warn!("failed to release dma buffer"); 333*bb4ee6a4SAndroid Build Coastguard Worker } 334*bb4ee6a4SAndroid Build Coastguard Worker } 335*bb4ee6a4SAndroid Build Coastguard Worker } 336*bb4ee6a4SAndroid Build Coastguard Worker 337*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 338*bb4ee6a4SAndroid Build Coastguard Worker } 339*bb4ee6a4SAndroid Build Coastguard Worker 340*bb4ee6a4SAndroid Build Coastguard Worker /// Perform a USB port reset to reinitialize a device. reset(&self) -> Result<()>341*bb4ee6a4SAndroid Build Coastguard Worker pub fn reset(&self) -> Result<()> { 342*bb4ee6a4SAndroid Build Coastguard Worker // TODO(dverkamp): re-enable reset once crbug.com/1058059 is resolved. 343*bb4ee6a4SAndroid Build Coastguard Worker // Skip reset for all non-Edge TPU devices. 344*bb4ee6a4SAndroid Build Coastguard Worker let vid = self.device_descriptor_tree.idVendor; 345*bb4ee6a4SAndroid Build Coastguard Worker let pid = self.device_descriptor_tree.idProduct; 346*bb4ee6a4SAndroid Build Coastguard Worker match (vid, pid) { 347*bb4ee6a4SAndroid Build Coastguard Worker (0x1a6e, 0x089a) => (), 348*bb4ee6a4SAndroid Build Coastguard Worker _ => return Ok(()), 349*bb4ee6a4SAndroid Build Coastguard Worker } 350*bb4ee6a4SAndroid Build Coastguard Worker 351*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 352*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor. 353*bb4ee6a4SAndroid Build Coastguard Worker let result = unsafe { self.ioctl(usb_sys::USBDEVFS_RESET) }; 354*bb4ee6a4SAndroid Build Coastguard Worker 355*bb4ee6a4SAndroid Build Coastguard Worker if let Err(Error::IoctlFailed(_nr, errno_err)) = result { 356*bb4ee6a4SAndroid Build Coastguard Worker // The device may disappear after a reset if e.g. its firmware changed. 357*bb4ee6a4SAndroid Build Coastguard Worker // Treat that as success. 358*bb4ee6a4SAndroid Build Coastguard Worker if errno_err.errno() == libc::ENODEV { 359*bb4ee6a4SAndroid Build Coastguard Worker return Ok(()); 360*bb4ee6a4SAndroid Build Coastguard Worker } 361*bb4ee6a4SAndroid Build Coastguard Worker } 362*bb4ee6a4SAndroid Build Coastguard Worker 363*bb4ee6a4SAndroid Build Coastguard Worker result?; 364*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 365*bb4ee6a4SAndroid Build Coastguard Worker } 366*bb4ee6a4SAndroid Build Coastguard Worker 367*bb4ee6a4SAndroid Build Coastguard Worker /// Claim an interface on this device. claim_interface(&self, interface_number: u8) -> Result<()>368*bb4ee6a4SAndroid Build Coastguard Worker pub fn claim_interface(&self, interface_number: u8) -> Result<()> { 369*bb4ee6a4SAndroid Build Coastguard Worker let disconnect_claim = usb_sys::usbdevfs_disconnect_claim { 370*bb4ee6a4SAndroid Build Coastguard Worker interface: interface_number.into(), 371*bb4ee6a4SAndroid Build Coastguard Worker flags: 0, 372*bb4ee6a4SAndroid Build Coastguard Worker driver: [0u8; 256], 373*bb4ee6a4SAndroid Build Coastguard Worker }; 374*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 375*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 376*bb4ee6a4SAndroid Build Coastguard Worker // pointer to a usbdevs_disconnect_claim structure. 377*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 378*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_DISCONNECT_CLAIM, &disconnect_claim)?; 379*bb4ee6a4SAndroid Build Coastguard Worker } 380*bb4ee6a4SAndroid Build Coastguard Worker 381*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 382*bb4ee6a4SAndroid Build Coastguard Worker } 383*bb4ee6a4SAndroid Build Coastguard Worker 384*bb4ee6a4SAndroid Build Coastguard Worker /// Release an interface previously claimed with `claim_interface()`. release_interface(&self, interface_number: u8) -> Result<()>385*bb4ee6a4SAndroid Build Coastguard Worker pub fn release_interface(&self, interface_number: u8) -> Result<()> { 386*bb4ee6a4SAndroid Build Coastguard Worker let ifnum: c_uint = interface_number.into(); 387*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 388*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 389*bb4ee6a4SAndroid Build Coastguard Worker // pointer to unsigned int. 390*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 391*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_RELEASEINTERFACE, &ifnum)?; 392*bb4ee6a4SAndroid Build Coastguard Worker } 393*bb4ee6a4SAndroid Build Coastguard Worker 394*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 395*bb4ee6a4SAndroid Build Coastguard Worker } 396*bb4ee6a4SAndroid Build Coastguard Worker 397*bb4ee6a4SAndroid Build Coastguard Worker /// Activate an alternate setting for an interface. set_interface_alt_setting( &self, interface_number: u8, alternative_setting: u8, ) -> Result<()>398*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_interface_alt_setting( 399*bb4ee6a4SAndroid Build Coastguard Worker &self, 400*bb4ee6a4SAndroid Build Coastguard Worker interface_number: u8, 401*bb4ee6a4SAndroid Build Coastguard Worker alternative_setting: u8, 402*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 403*bb4ee6a4SAndroid Build Coastguard Worker let setinterface = usb_sys::usbdevfs_setinterface { 404*bb4ee6a4SAndroid Build Coastguard Worker interface: interface_number.into(), 405*bb4ee6a4SAndroid Build Coastguard Worker altsetting: alternative_setting.into(), 406*bb4ee6a4SAndroid Build Coastguard Worker }; 407*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 408*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 409*bb4ee6a4SAndroid Build Coastguard Worker // pointer to a usbdevfs_setinterface structure. 410*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 411*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_SETINTERFACE, &setinterface)?; 412*bb4ee6a4SAndroid Build Coastguard Worker } 413*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 414*bb4ee6a4SAndroid Build Coastguard Worker } 415*bb4ee6a4SAndroid Build Coastguard Worker 416*bb4ee6a4SAndroid Build Coastguard Worker /// Set active configuration for this device. set_active_configuration(&mut self, config: u8) -> Result<()>417*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_active_configuration(&mut self, config: u8) -> Result<()> { 418*bb4ee6a4SAndroid Build Coastguard Worker let config: c_int = config.into(); 419*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 420*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 421*bb4ee6a4SAndroid Build Coastguard Worker // pointer to int. 422*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 423*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_SETCONFIGURATION, &config)?; 424*bb4ee6a4SAndroid Build Coastguard Worker } 425*bb4ee6a4SAndroid Build Coastguard Worker 426*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 427*bb4ee6a4SAndroid Build Coastguard Worker } 428*bb4ee6a4SAndroid Build Coastguard Worker 429*bb4ee6a4SAndroid Build Coastguard Worker /// Get the device descriptor of this device. get_device_descriptor(&self) -> Result<DeviceDescriptor>430*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_device_descriptor(&self) -> Result<DeviceDescriptor> { 431*bb4ee6a4SAndroid Build Coastguard Worker Ok(*self.device_descriptor_tree) 432*bb4ee6a4SAndroid Build Coastguard Worker } 433*bb4ee6a4SAndroid Build Coastguard Worker get_device_descriptor_tree(&self) -> &DeviceDescriptorTree434*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_device_descriptor_tree(&self) -> &DeviceDescriptorTree { 435*bb4ee6a4SAndroid Build Coastguard Worker &self.device_descriptor_tree 436*bb4ee6a4SAndroid Build Coastguard Worker } 437*bb4ee6a4SAndroid Build Coastguard Worker 438*bb4ee6a4SAndroid Build Coastguard Worker /// Get active config descriptor of this device. get_config_descriptor(&self, config: u8) -> Result<ConfigDescriptorTree>439*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_config_descriptor(&self, config: u8) -> Result<ConfigDescriptorTree> { 440*bb4ee6a4SAndroid Build Coastguard Worker match self.device_descriptor_tree.get_config_descriptor(config) { 441*bb4ee6a4SAndroid Build Coastguard Worker Some(config_descriptor) => Ok(config_descriptor.clone()), 442*bb4ee6a4SAndroid Build Coastguard Worker None => Err(Error::NoSuchDescriptor), 443*bb4ee6a4SAndroid Build Coastguard Worker } 444*bb4ee6a4SAndroid Build Coastguard Worker } 445*bb4ee6a4SAndroid Build Coastguard Worker 446*bb4ee6a4SAndroid Build Coastguard Worker /// Get a configuration descriptor by its index within the list of descriptors returned 447*bb4ee6a4SAndroid Build Coastguard Worker /// by the device. get_config_descriptor_by_index(&self, config_index: u8) -> Result<ConfigDescriptorTree>448*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_config_descriptor_by_index(&self, config_index: u8) -> Result<ConfigDescriptorTree> { 449*bb4ee6a4SAndroid Build Coastguard Worker match self 450*bb4ee6a4SAndroid Build Coastguard Worker .device_descriptor_tree 451*bb4ee6a4SAndroid Build Coastguard Worker .get_config_descriptor_by_index(config_index) 452*bb4ee6a4SAndroid Build Coastguard Worker { 453*bb4ee6a4SAndroid Build Coastguard Worker Some(config_descriptor) => Ok(config_descriptor.clone()), 454*bb4ee6a4SAndroid Build Coastguard Worker None => Err(Error::NoSuchDescriptor), 455*bb4ee6a4SAndroid Build Coastguard Worker } 456*bb4ee6a4SAndroid Build Coastguard Worker } 457*bb4ee6a4SAndroid Build Coastguard Worker 458*bb4ee6a4SAndroid Build Coastguard Worker /// Get bConfigurationValue of the currently active configuration. get_active_configuration(&self) -> Result<u8>459*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_active_configuration(&self) -> Result<u8> { 460*bb4ee6a4SAndroid Build Coastguard Worker // If the device only exposes a single configuration, bypass the control transfer below 461*bb4ee6a4SAndroid Build Coastguard Worker // by looking up the configuration value from the descriptor. 462*bb4ee6a4SAndroid Build Coastguard Worker if self.device_descriptor_tree.bNumConfigurations == 1 { 463*bb4ee6a4SAndroid Build Coastguard Worker if let Some(config_descriptor) = self 464*bb4ee6a4SAndroid Build Coastguard Worker .device_descriptor_tree 465*bb4ee6a4SAndroid Build Coastguard Worker .get_config_descriptor_by_index(0) 466*bb4ee6a4SAndroid Build Coastguard Worker { 467*bb4ee6a4SAndroid Build Coastguard Worker return Ok(config_descriptor.bConfigurationValue); 468*bb4ee6a4SAndroid Build Coastguard Worker } 469*bb4ee6a4SAndroid Build Coastguard Worker } 470*bb4ee6a4SAndroid Build Coastguard Worker 471*bb4ee6a4SAndroid Build Coastguard Worker // Send a synchronous control transfer to get the active configuration. 472*bb4ee6a4SAndroid Build Coastguard Worker let mut active_config: u8 = 0; 473*bb4ee6a4SAndroid Build Coastguard Worker let ctrl_transfer = usb_sys::usbdevfs_ctrltransfer { 474*bb4ee6a4SAndroid Build Coastguard Worker bRequestType: control_request_type( 475*bb4ee6a4SAndroid Build Coastguard Worker ControlRequestType::Standard, 476*bb4ee6a4SAndroid Build Coastguard Worker ControlRequestDataPhaseTransferDirection::DeviceToHost, 477*bb4ee6a4SAndroid Build Coastguard Worker ControlRequestRecipient::Device, 478*bb4ee6a4SAndroid Build Coastguard Worker ), 479*bb4ee6a4SAndroid Build Coastguard Worker bRequest: StandardControlRequest::GetConfiguration as u8, 480*bb4ee6a4SAndroid Build Coastguard Worker wValue: 0, 481*bb4ee6a4SAndroid Build Coastguard Worker wIndex: 0, 482*bb4ee6a4SAndroid Build Coastguard Worker wLength: size_of_val(&active_config) as u16, 483*bb4ee6a4SAndroid Build Coastguard Worker timeout: 5000, // milliseconds 484*bb4ee6a4SAndroid Build Coastguard Worker data: &mut active_config as *mut u8 as *mut c_void, 485*bb4ee6a4SAndroid Build Coastguard Worker }; 486*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 487*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 488*bb4ee6a4SAndroid Build Coastguard Worker // pointer to a usbdevfs_ctrltransfer structure. 489*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 490*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_CONTROL, &ctrl_transfer)?; 491*bb4ee6a4SAndroid Build Coastguard Worker } 492*bb4ee6a4SAndroid Build Coastguard Worker Ok(active_config) 493*bb4ee6a4SAndroid Build Coastguard Worker } 494*bb4ee6a4SAndroid Build Coastguard Worker 495*bb4ee6a4SAndroid Build Coastguard Worker /// Get the total number of configurations for this device. get_num_configurations(&self) -> u8496*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_num_configurations(&self) -> u8 { 497*bb4ee6a4SAndroid Build Coastguard Worker self.device_descriptor_tree.bNumConfigurations 498*bb4ee6a4SAndroid Build Coastguard Worker } 499*bb4ee6a4SAndroid Build Coastguard Worker 500*bb4ee6a4SAndroid Build Coastguard Worker /// Clear the halt/stall condition for an endpoint. clear_halt(&self, ep_addr: u8) -> Result<()>501*bb4ee6a4SAndroid Build Coastguard Worker pub fn clear_halt(&self, ep_addr: u8) -> Result<()> { 502*bb4ee6a4SAndroid Build Coastguard Worker let endpoint: c_uint = ep_addr.into(); 503*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 504*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 505*bb4ee6a4SAndroid Build Coastguard Worker // pointer to unsigned int. 506*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 507*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_CLEAR_HALT, &endpoint)?; 508*bb4ee6a4SAndroid Build Coastguard Worker } 509*bb4ee6a4SAndroid Build Coastguard Worker 510*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 511*bb4ee6a4SAndroid Build Coastguard Worker } 512*bb4ee6a4SAndroid Build Coastguard Worker 513*bb4ee6a4SAndroid Build Coastguard Worker /// Get speed of this device. get_speed(&self) -> Result<Option<DeviceSpeed>>514*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_speed(&self) -> Result<Option<DeviceSpeed>> { 515*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: args are valid and the return value is checked 516*bb4ee6a4SAndroid Build Coastguard Worker let speed = unsafe { self.ioctl(usb_sys::USBDEVFS_GET_SPEED) }?; 517*bb4ee6a4SAndroid Build Coastguard Worker match speed { 518*bb4ee6a4SAndroid Build Coastguard Worker 1 => Ok(Some(DeviceSpeed::Low)), // Low Speed 519*bb4ee6a4SAndroid Build Coastguard Worker 2 => Ok(Some(DeviceSpeed::Full)), // Full Speed 520*bb4ee6a4SAndroid Build Coastguard Worker 3 => Ok(Some(DeviceSpeed::High)), // High Speed 521*bb4ee6a4SAndroid Build Coastguard Worker 4 => Ok(Some(DeviceSpeed::High)), // Wireless, treat as a High Speed device 522*bb4ee6a4SAndroid Build Coastguard Worker 5 => Ok(Some(DeviceSpeed::Super)), // Super Speed 523*bb4ee6a4SAndroid Build Coastguard Worker 6 => Ok(Some(DeviceSpeed::SuperPlus)), // Super Speed Plus 524*bb4ee6a4SAndroid Build Coastguard Worker _ => { 525*bb4ee6a4SAndroid Build Coastguard Worker error!("unexpected speed: {:?}", speed); 526*bb4ee6a4SAndroid Build Coastguard Worker Ok(None) 527*bb4ee6a4SAndroid Build Coastguard Worker } 528*bb4ee6a4SAndroid Build Coastguard Worker } 529*bb4ee6a4SAndroid Build Coastguard Worker } 530*bb4ee6a4SAndroid Build Coastguard Worker 531*bb4ee6a4SAndroid Build Coastguard Worker /// Allocate streams for the endpoint alloc_streams(&self, ep: u8, num_streams: u16) -> Result<()>532*bb4ee6a4SAndroid Build Coastguard Worker pub fn alloc_streams(&self, ep: u8, num_streams: u16) -> Result<()> { 533*bb4ee6a4SAndroid Build Coastguard Worker let mut streams = vec_with_array_field::<usb_sys::usbdevfs_streams, c_uchar>(1); 534*bb4ee6a4SAndroid Build Coastguard Worker streams[0].num_streams = num_streams as c_uint; 535*bb4ee6a4SAndroid Build Coastguard Worker streams[0].num_eps = 1 as c_uint; 536*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 537*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we have allocated enough memory 538*bb4ee6a4SAndroid Build Coastguard Worker let eps = unsafe { streams[0].eps.as_mut_slice(1) }; 539*bb4ee6a4SAndroid Build Coastguard Worker eps[0] = ep as c_uchar; 540*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 541*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 542*bb4ee6a4SAndroid Build Coastguard Worker // pointer to a usbdevfs_streams structure. 543*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 544*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_ALLOC_STREAMS, &streams[0])?; 545*bb4ee6a4SAndroid Build Coastguard Worker } 546*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 547*bb4ee6a4SAndroid Build Coastguard Worker } 548*bb4ee6a4SAndroid Build Coastguard Worker 549*bb4ee6a4SAndroid Build Coastguard Worker /// Free streams for the endpoint free_streams(&self, ep: u8) -> Result<()>550*bb4ee6a4SAndroid Build Coastguard Worker pub fn free_streams(&self, ep: u8) -> Result<()> { 551*bb4ee6a4SAndroid Build Coastguard Worker let mut streams = vec_with_array_field::<usb_sys::usbdevfs_streams, c_uchar>(1); 552*bb4ee6a4SAndroid Build Coastguard Worker streams[0].num_eps = 1 as c_uint; 553*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 554*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we have allocated enough memory 555*bb4ee6a4SAndroid Build Coastguard Worker let eps = unsafe { streams[0].eps.as_mut_slice(1) }; 556*bb4ee6a4SAndroid Build Coastguard Worker eps[0] = ep as c_uchar; 557*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 558*bb4ee6a4SAndroid Build Coastguard Worker // Safe because self.fd is a valid usbdevfs file descriptor and we pass a valid 559*bb4ee6a4SAndroid Build Coastguard Worker // pointer to a usbdevfs_streams structure. 560*bb4ee6a4SAndroid Build Coastguard Worker unsafe { 561*bb4ee6a4SAndroid Build Coastguard Worker self.ioctl_with_ref(usb_sys::USBDEVFS_FREE_STREAMS, &streams[0])?; 562*bb4ee6a4SAndroid Build Coastguard Worker } 563*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 564*bb4ee6a4SAndroid Build Coastguard Worker } 565*bb4ee6a4SAndroid Build Coastguard Worker } 566*bb4ee6a4SAndroid Build Coastguard Worker 567*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for Device { as_raw_descriptor(&self) -> RawDescriptor568*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor { 569*bb4ee6a4SAndroid Build Coastguard Worker self.fd.as_raw_descriptor() 570*bb4ee6a4SAndroid Build Coastguard Worker } 571*bb4ee6a4SAndroid Build Coastguard Worker } 572*bb4ee6a4SAndroid Build Coastguard Worker 573*bb4ee6a4SAndroid Build Coastguard Worker impl Transfer { urb(&self) -> &usb_sys::usbdevfs_urb574*bb4ee6a4SAndroid Build Coastguard Worker fn urb(&self) -> &usb_sys::usbdevfs_urb { 575*bb4ee6a4SAndroid Build Coastguard Worker // self.urb is a Vec created with `vec_with_array_field`; the first entry is 576*bb4ee6a4SAndroid Build Coastguard Worker // the URB itself. 577*bb4ee6a4SAndroid Build Coastguard Worker &self.urb[0] 578*bb4ee6a4SAndroid Build Coastguard Worker } 579*bb4ee6a4SAndroid Build Coastguard Worker urb_mut(&mut self) -> &mut usb_sys::usbdevfs_urb580*bb4ee6a4SAndroid Build Coastguard Worker fn urb_mut(&mut self) -> &mut usb_sys::usbdevfs_urb { 581*bb4ee6a4SAndroid Build Coastguard Worker &mut self.urb[0] 582*bb4ee6a4SAndroid Build Coastguard Worker } 583*bb4ee6a4SAndroid Build Coastguard Worker new( transfer_type: u8, endpoint: u8, buffer: TransferBuffer, iso_packets: &[usb_sys::usbdevfs_iso_packet_desc], ) -> Result<Transfer>584*bb4ee6a4SAndroid Build Coastguard Worker fn new( 585*bb4ee6a4SAndroid Build Coastguard Worker transfer_type: u8, 586*bb4ee6a4SAndroid Build Coastguard Worker endpoint: u8, 587*bb4ee6a4SAndroid Build Coastguard Worker buffer: TransferBuffer, 588*bb4ee6a4SAndroid Build Coastguard Worker iso_packets: &[usb_sys::usbdevfs_iso_packet_desc], 589*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Transfer> { 590*bb4ee6a4SAndroid Build Coastguard Worker let mut transfer = Transfer { 591*bb4ee6a4SAndroid Build Coastguard Worker urb: vec_with_array_field::<usb_sys::usbdevfs_urb, usb_sys::usbdevfs_iso_packet_desc>( 592*bb4ee6a4SAndroid Build Coastguard Worker iso_packets.len(), 593*bb4ee6a4SAndroid Build Coastguard Worker ), 594*bb4ee6a4SAndroid Build Coastguard Worker buffer, 595*bb4ee6a4SAndroid Build Coastguard Worker callback: None, 596*bb4ee6a4SAndroid Build Coastguard Worker }; 597*bb4ee6a4SAndroid Build Coastguard Worker 598*bb4ee6a4SAndroid Build Coastguard Worker transfer.urb_mut().urb_type = transfer_type; 599*bb4ee6a4SAndroid Build Coastguard Worker transfer.urb_mut().endpoint = endpoint; 600*bb4ee6a4SAndroid Build Coastguard Worker transfer.urb_mut().buffer = transfer.buffer.address().ok_or(Error::InvalidBuffer)?; 601*bb4ee6a4SAndroid Build Coastguard Worker transfer.urb_mut().buffer_length = transfer 602*bb4ee6a4SAndroid Build Coastguard Worker .buffer 603*bb4ee6a4SAndroid Build Coastguard Worker .size() 604*bb4ee6a4SAndroid Build Coastguard Worker .ok_or(Error::InvalidBuffer)? 605*bb4ee6a4SAndroid Build Coastguard Worker .try_into() 606*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::InvalidBufferLength)?; 607*bb4ee6a4SAndroid Build Coastguard Worker 608*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 609*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we ensured there is enough space in transfer.urb to hold the number of 610*bb4ee6a4SAndroid Build Coastguard Worker // isochronous frames required. 611*bb4ee6a4SAndroid Build Coastguard Worker let iso_frame_desc = unsafe { 612*bb4ee6a4SAndroid Build Coastguard Worker transfer 613*bb4ee6a4SAndroid Build Coastguard Worker .urb_mut() 614*bb4ee6a4SAndroid Build Coastguard Worker .iso_frame_desc 615*bb4ee6a4SAndroid Build Coastguard Worker .as_mut_slice(iso_packets.len()) 616*bb4ee6a4SAndroid Build Coastguard Worker }; 617*bb4ee6a4SAndroid Build Coastguard Worker iso_frame_desc.copy_from_slice(iso_packets); 618*bb4ee6a4SAndroid Build Coastguard Worker 619*bb4ee6a4SAndroid Build Coastguard Worker Ok(transfer) 620*bb4ee6a4SAndroid Build Coastguard Worker } 621*bb4ee6a4SAndroid Build Coastguard Worker 622*bb4ee6a4SAndroid Build Coastguard Worker /// Create a control transfer. new_control(buffer: TransferBuffer) -> Result<Transfer>623*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_control(buffer: TransferBuffer) -> Result<Transfer> { 624*bb4ee6a4SAndroid Build Coastguard Worker let endpoint = 0; 625*bb4ee6a4SAndroid Build Coastguard Worker Self::new(usb_sys::USBDEVFS_URB_TYPE_CONTROL, endpoint, buffer, &[]) 626*bb4ee6a4SAndroid Build Coastguard Worker } 627*bb4ee6a4SAndroid Build Coastguard Worker 628*bb4ee6a4SAndroid Build Coastguard Worker /// Create an interrupt transfer. new_interrupt(endpoint: u8, buffer: TransferBuffer) -> Result<Transfer>629*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_interrupt(endpoint: u8, buffer: TransferBuffer) -> Result<Transfer> { 630*bb4ee6a4SAndroid Build Coastguard Worker Self::new(usb_sys::USBDEVFS_URB_TYPE_INTERRUPT, endpoint, buffer, &[]) 631*bb4ee6a4SAndroid Build Coastguard Worker } 632*bb4ee6a4SAndroid Build Coastguard Worker 633*bb4ee6a4SAndroid Build Coastguard Worker /// Create a bulk transfer. new_bulk( endpoint: u8, buffer: TransferBuffer, stream_id: Option<u16>, ) -> Result<Transfer>634*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_bulk( 635*bb4ee6a4SAndroid Build Coastguard Worker endpoint: u8, 636*bb4ee6a4SAndroid Build Coastguard Worker buffer: TransferBuffer, 637*bb4ee6a4SAndroid Build Coastguard Worker stream_id: Option<u16>, 638*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Transfer> { 639*bb4ee6a4SAndroid Build Coastguard Worker let mut transfer = Self::new(usb_sys::USBDEVFS_URB_TYPE_BULK, endpoint, buffer, &[])?; 640*bb4ee6a4SAndroid Build Coastguard Worker if let Some(stream_id) = stream_id { 641*bb4ee6a4SAndroid Build Coastguard Worker transfer.urb_mut().number_of_packets_or_stream_id = stream_id as u32; 642*bb4ee6a4SAndroid Build Coastguard Worker } 643*bb4ee6a4SAndroid Build Coastguard Worker Ok(transfer) 644*bb4ee6a4SAndroid Build Coastguard Worker } 645*bb4ee6a4SAndroid Build Coastguard Worker 646*bb4ee6a4SAndroid Build Coastguard Worker /// Create an isochronous transfer. new_isochronous(endpoint: u8, buffer: TransferBuffer) -> Result<Transfer>647*bb4ee6a4SAndroid Build Coastguard Worker pub fn new_isochronous(endpoint: u8, buffer: TransferBuffer) -> Result<Transfer> { 648*bb4ee6a4SAndroid Build Coastguard Worker // TODO(dverkamp): allow user to specify iso descriptors 649*bb4ee6a4SAndroid Build Coastguard Worker Self::new(usb_sys::USBDEVFS_URB_TYPE_ISO, endpoint, buffer, &[]) 650*bb4ee6a4SAndroid Build Coastguard Worker } 651*bb4ee6a4SAndroid Build Coastguard Worker 652*bb4ee6a4SAndroid Build Coastguard Worker /// Get the status of a completed transfer. status(&self) -> TransferStatus653*bb4ee6a4SAndroid Build Coastguard Worker pub fn status(&self) -> TransferStatus { 654*bb4ee6a4SAndroid Build Coastguard Worker let status = self.urb().status; 655*bb4ee6a4SAndroid Build Coastguard Worker if status == 0 { 656*bb4ee6a4SAndroid Build Coastguard Worker TransferStatus::Completed 657*bb4ee6a4SAndroid Build Coastguard Worker } else if status == -ENODEV { 658*bb4ee6a4SAndroid Build Coastguard Worker TransferStatus::NoDevice 659*bb4ee6a4SAndroid Build Coastguard Worker } else if status == -ENOENT { 660*bb4ee6a4SAndroid Build Coastguard Worker TransferStatus::Cancelled 661*bb4ee6a4SAndroid Build Coastguard Worker } else if status == -EPIPE { 662*bb4ee6a4SAndroid Build Coastguard Worker TransferStatus::Stalled 663*bb4ee6a4SAndroid Build Coastguard Worker } else { 664*bb4ee6a4SAndroid Build Coastguard Worker TransferStatus::Error 665*bb4ee6a4SAndroid Build Coastguard Worker } 666*bb4ee6a4SAndroid Build Coastguard Worker } 667*bb4ee6a4SAndroid Build Coastguard Worker 668*bb4ee6a4SAndroid Build Coastguard Worker /// Get the actual amount of data transferred, which may be less than 669*bb4ee6a4SAndroid Build Coastguard Worker /// the original length. actual_length(&self) -> usize670*bb4ee6a4SAndroid Build Coastguard Worker pub fn actual_length(&self) -> usize { 671*bb4ee6a4SAndroid Build Coastguard Worker self.urb().actual_length as usize 672*bb4ee6a4SAndroid Build Coastguard Worker } 673*bb4ee6a4SAndroid Build Coastguard Worker 674*bb4ee6a4SAndroid Build Coastguard Worker /// Set callback function for transfer completion. set_callback<C: 'static + Fn(Transfer) + Send + Sync>(&mut self, cb: C)675*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_callback<C: 'static + Fn(Transfer) + Send + Sync>(&mut self, cb: C) { 676*bb4ee6a4SAndroid Build Coastguard Worker self.callback = Some(Box::new(cb)); 677*bb4ee6a4SAndroid Build Coastguard Worker } 678*bb4ee6a4SAndroid Build Coastguard Worker } 679*bb4ee6a4SAndroid Build Coastguard Worker 680*bb4ee6a4SAndroid Build Coastguard Worker impl TransferHandle { 681*bb4ee6a4SAndroid Build Coastguard Worker /// Attempt to cancel the transfer associated with this `TransferHandle`. 682*bb4ee6a4SAndroid Build Coastguard Worker /// Safe to call even if the transfer has already completed; 683*bb4ee6a4SAndroid Build Coastguard Worker /// `Error::TransferAlreadyCompleted` will be returned in this case. cancel(&self) -> Result<()>684*bb4ee6a4SAndroid Build Coastguard Worker pub fn cancel(&self) -> Result<()> { 685*bb4ee6a4SAndroid Build Coastguard Worker let rc_transfer = match self.weak_transfer.upgrade() { 686*bb4ee6a4SAndroid Build Coastguard Worker None => return Err(Error::TransferAlreadyCompleted), 687*bb4ee6a4SAndroid Build Coastguard Worker Some(rc_transfer) => rc_transfer, 688*bb4ee6a4SAndroid Build Coastguard Worker }; 689*bb4ee6a4SAndroid Build Coastguard Worker 690*bb4ee6a4SAndroid Build Coastguard Worker let urb_ptr = rc_transfer.urb.as_ptr() as *mut usb_sys::usbdevfs_urb; 691*bb4ee6a4SAndroid Build Coastguard Worker let fd = match self.fd.upgrade() { 692*bb4ee6a4SAndroid Build Coastguard Worker None => return Err(Error::NoDevice), 693*bb4ee6a4SAndroid Build Coastguard Worker Some(fd) => fd, 694*bb4ee6a4SAndroid Build Coastguard Worker }; 695*bb4ee6a4SAndroid Build Coastguard Worker 696*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: 697*bb4ee6a4SAndroid Build Coastguard Worker // Safe because fd is a valid usbdevfs file descriptor and we pass a valid 698*bb4ee6a4SAndroid Build Coastguard Worker // pointer to a usbdevfs_urb structure. 699*bb4ee6a4SAndroid Build Coastguard Worker if unsafe { 700*bb4ee6a4SAndroid Build Coastguard Worker handle_eintr_errno!(base::ioctl_with_mut_ptr( 701*bb4ee6a4SAndroid Build Coastguard Worker &*fd, 702*bb4ee6a4SAndroid Build Coastguard Worker usb_sys::USBDEVFS_DISCARDURB, 703*bb4ee6a4SAndroid Build Coastguard Worker urb_ptr 704*bb4ee6a4SAndroid Build Coastguard Worker )) 705*bb4ee6a4SAndroid Build Coastguard Worker } < 0 706*bb4ee6a4SAndroid Build Coastguard Worker { 707*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::IoctlFailed( 708*bb4ee6a4SAndroid Build Coastguard Worker usb_sys::USBDEVFS_DISCARDURB, 709*bb4ee6a4SAndroid Build Coastguard Worker base::Error::last(), 710*bb4ee6a4SAndroid Build Coastguard Worker )); 711*bb4ee6a4SAndroid Build Coastguard Worker } 712*bb4ee6a4SAndroid Build Coastguard Worker 713*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 714*bb4ee6a4SAndroid Build Coastguard Worker } 715*bb4ee6a4SAndroid Build Coastguard Worker } 716