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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// SPDX-License-Identifier: MIT
use crate::*;
/// Trait containing the rest of[`struct@FwIsoIt`] methods.
///
/// # Implementors
///
/// [`FwIsoIt`][struct@crate::FwIsoIt]
pub trait FwIsoItExtManual {
/// Register packet data with header and payload for IT context. The content of given header and
/// payload is appended into data field of isochronous packet to be sent. The caller can schedule
/// hardware interrupt to generate interrupt event. In detail, please refer to documentation about
/// [`interrupted`][struct@crate::FwIsoIt#interrupted].
/// ## `tags`
/// The value of tag field for isochronous packet to register.
/// ## `sync_code`
/// The value of sync field in isochronous packet header for packet processing, up to 15.
/// ## `header`
/// The header of IT context for isochronous
/// packet. The length of header should be the same as the size of header indicated in
/// allocation if it's not null.
/// ## `payload`
/// The payload of IT context for isochronous
/// packet.
/// ## `schedule_interrupt`
/// Whether to schedule hardware interrupt at isochronous cycle for the packet.
///
/// # Returns
///
/// TRUE if the overall operation finishes successful, otherwise FALSE.
#[doc(alias = "hinoko_fw_iso_it_register_packet")]
fn register_packet(
&self,
tags: FwIsoCtxMatchFlag,
sy: u32,
header: Option<&[u8]>,
payload: Option<&[u8]>,
schedule_interrupt: bool,
) -> Result<(), Error>;
/// Start IT context.
/// ## `cycle_match`
/// The isochronous cycle
/// to start packet processing. The first element should be the second part of
/// isochronous cycle, up to 3. The second element should be the cycle part of
/// isochronous cycle, up to 7999.
///
/// # Returns
///
/// TRUE if the overall operation finishes successful, otherwise FALSE.
#[doc(alias = "hinoko_fw_iso_it_start")]
fn start(&self, cycle_match: Option<&[u16; 2]>) -> Result<(), Error>;
/// Emitted when Linux FireWire subsystem generates interrupt event. There are three cases
/// for Linux FireWire subsystem to generate the event:
///
/// - When 1394 OHCI hardware generates hardware interrupt as a result of processing the
/// isochronous packet for the buffer chunk marked to generate hardware interrupt.
/// - When the number of isochronous packets sent since the last interrupt event reaches
/// one quarter of memory page size (usually 4,096 / 4 = 1,024 packets).
/// - When application calls [`FwIsoCtxExt::flush_completions()`][crate::prelude::FwIsoCtxExt::flush_completions()] explicitly.
/// ## `sec`
/// sec part of isochronous cycle when interrupt occurs, up to 7.
/// ## `cycle`
/// cycle part of of isochronous cycle when interrupt occurs, up to 7999.
/// ## `tstamp`
/// A series of timestamps for
/// packets already handled.
/// ## `count`
/// the number of handled packets.
#[doc(alias = "interrupted")]
fn connect_interrupted<F>(&self, f: F) -> SignalHandlerId
where
F: Fn(&Self, u32, u32, &[u8], u32) + 'static;
}
impl<O: IsA<FwIsoIt>> FwIsoItExtManual for O {
fn register_packet(
&self,
tags: FwIsoCtxMatchFlag,
sy: u32,
header: Option<&[u8]>,
payload: Option<&[u8]>,
schedule_interrupt: bool,
) -> Result<(), Error> {
let (header_ptr, header_length) = match header {
Some(h) => (h.as_ptr(), h.len() as u32),
None => (std::ptr::null(), 0),
};
let (payload_ptr, payload_length) = match payload {
Some(p) => (p.as_ptr(), p.len() as u32),
None => (std::ptr::null(), 0),
};
unsafe {
let mut error = std::ptr::null_mut();
let is_ok = ffi::hinoko_fw_iso_it_register_packet(
self.as_ref().to_glib_none().0,
tags.into_glib(),
sy,
header_ptr,
header_length,
payload_ptr,
payload_length,
schedule_interrupt.into_glib(),
&mut error,
);
debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(())
} else {
Err(from_glib_full(error))
}
}
}
fn start(&self, cycle_match: Option<&[u16; 2]>) -> Result<(), Error> {
unsafe {
let ptr: *const [u16; 2] = match cycle_match {
Some(data) => data,
None => std::ptr::null_mut(),
};
let mut error = std::ptr::null_mut();
let is_ok =
ffi::hinoko_fw_iso_it_start(self.as_ref().to_glib_none().0, ptr, &mut error);
debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
if error.is_null() {
Ok(())
} else {
Err(from_glib_full(error))
}
}
}
fn connect_interrupted<F>(&self, f: F) -> SignalHandlerId
where
F: Fn(&Self, u32, u32, &[u8], u32) + 'static,
{
unsafe extern "C" fn interrupted_trampoline<P, F>(
this: *mut ffi::HinokoFwIsoIt,
sec: std::ffi::c_uint,
cycle: std::ffi::c_uint,
header: *const u8,
header_length: std::ffi::c_uint,
count: std::ffi::c_uint,
f: glib::ffi::gpointer,
) where
P: IsA<FwIsoIt>,
F: Fn(&P, u32, u32, &[u8], u32) + 'static,
{
let f: &F = &*(f as *const F);
f(
&FwIsoIt::from_glib_borrow(this).unsafe_cast_ref(),
sec,
cycle,
std::slice::from_raw_parts(header, header_length as usize),
count,
)
}
unsafe {
let f: std::boxed::Box<F> = std::boxed::Box::new(f);
connect_raw(
self.as_ptr() as *mut _,
c"interrupted".as_ptr() as *const _,
Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
interrupted_trampoline::<Self, F> as *const (),
)),
std::boxed::Box::into_raw(f),
)
}
}
}