1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use std::mem;
use std::sync::Arc;
use base::debug;
use base::error;
use base::warn;
use usb_util::Device;
use usb_util::Transfer;
use usb_util::TransferStatus;
use super::error::*;
use crate::usb::xhci::xhci_transfer::XhciTransfer;
use crate::usb::xhci::xhci_transfer::XhciTransferState;
use crate::utils::AsyncJobQueue;
use crate::utils::FailHandle;
pub fn update_transfer_state(
xhci_transfer: &Arc<XhciTransfer>,
usb_transfer: &Transfer,
) -> Result<()> {
let status = usb_transfer.status();
let mut state = xhci_transfer.state().lock();
if status == TransferStatus::Cancelled {
*state = XhciTransferState::Cancelled;
return Ok(());
}
match *state {
XhciTransferState::Cancelling => {
*state = XhciTransferState::Cancelled;
}
XhciTransferState::Submitted { .. } => {
*state = XhciTransferState::Completed;
}
_ => {
error!("xhci trasfer state is invalid");
*state = XhciTransferState::Completed;
return Err(Error::BadXhciTransferState);
}
}
Ok(())
}
pub fn submit_transfer(
fail_handle: Arc<dyn FailHandle>,
job_queue: &Arc<AsyncJobQueue>,
xhci_transfer: Arc<XhciTransfer>,
device: &mut Device,
usb_transfer: Transfer,
) -> Result<()> {
let transfer_status = {
let mut state = xhci_transfer.state().lock();
match mem::replace(&mut *state, XhciTransferState::Cancelled) {
XhciTransferState::Created => {
match device.submit_transfer(usb_transfer) {
Err(e) => {
error!("fail to submit transfer {:?}", e);
*state = XhciTransferState::Completed;
TransferStatus::NoDevice
}
Ok(canceller) => {
let cancel_callback = Box::new(move || match canceller.cancel() {
Ok(()) => {
debug!("cancel issued to kernel");
}
Err(e) => {
error!("failed to cancel XhciTransfer: {}", e);
}
});
*state = XhciTransferState::Submitted { cancel_callback };
return Ok(());
}
}
}
XhciTransferState::Cancelled => {
warn!("Transfer is already cancelled");
TransferStatus::Cancelled
}
_ => {
error!("xhci trasfer state is invalid");
return Err(Error::BadXhciTransferState);
}
}
};
job_queue
.queue_job(
move || match xhci_transfer.on_transfer_complete(&transfer_status, 0) {
Ok(_) => {}
Err(e) => {
error!("transfer complete failed: {:?}", e);
fail_handle.fail();
}
},
)
.map_err(Error::QueueAsyncJob)
}