1#![deny(missing_docs)]
6
7use std::any::Any;
16use std::cmp::{Ord, PartialOrd};
17use std::convert::TryFrom;
18use std::sync::Mutex;
19
20use self::resources::DeviceResources;
21
22pub mod device_manager;
23pub mod resources;
24
25#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
27pub struct IoSize(pub u64);
28
29impl IoSize {
30 #[inline]
32 pub fn raw_value(self) -> u64 {
33 self.0
34 }
35}
36
37impl From<u64> for IoSize {
38 #[inline]
39 fn from(size: u64) -> Self {
40 IoSize(size)
41 }
42}
43
44impl From<IoSize> for u64 {
45 #[inline]
46 fn from(size: IoSize) -> Self {
47 size.0
48 }
49}
50
51#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
53pub struct IoAddress(pub u64);
54
55impl IoAddress {
56 #[inline]
58 pub fn raw_value(self) -> u64 {
59 self.0
60 }
61}
62
63impl From<u64> for IoAddress {
64 #[inline]
65 fn from(addr: u64) -> Self {
66 IoAddress(addr)
67 }
68}
69
70impl From<IoAddress> for u64 {
71 #[inline]
72 fn from(addr: IoAddress) -> Self {
73 addr.0
74 }
75}
76
77type PioAddressType = u16;
78
79#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
81pub struct PioSize(pub PioAddressType);
82
83impl PioSize {
84 #[inline]
86 pub fn raw_value(self) -> PioAddressType {
87 self.0
88 }
89}
90
91impl From<PioAddressType> for PioSize {
92 #[inline]
93 fn from(size: PioAddressType) -> Self {
94 PioSize(size)
95 }
96}
97
98impl From<PioSize> for PioAddressType {
99 #[inline]
100 fn from(size: PioSize) -> Self {
101 size.0
102 }
103}
104
105impl TryFrom<IoSize> for PioSize {
106 type Error = IoSize;
107
108 #[inline]
109 fn try_from(size: IoSize) -> Result<Self, Self::Error> {
110 if size.raw_value() <= std::u16::MAX as u64 {
111 Ok(PioSize(size.raw_value() as PioAddressType))
112 } else {
113 Err(size)
114 }
115 }
116}
117
118impl From<PioSize> for IoSize {
119 #[inline]
120 fn from(size: PioSize) -> Self {
121 IoSize(size.raw_value() as u64)
122 }
123}
124
125#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
127pub struct PioAddress(pub PioAddressType);
128
129impl PioAddress {
130 #[inline]
132 pub fn raw_value(self) -> PioAddressType {
133 self.0
134 }
135}
136
137impl From<PioAddressType> for PioAddress {
138 #[inline]
139 fn from(addr: PioAddressType) -> Self {
140 PioAddress(addr)
141 }
142}
143
144impl From<PioAddress> for PioAddressType {
145 #[inline]
146 fn from(addr: PioAddress) -> Self {
147 addr.0
148 }
149}
150
151impl TryFrom<IoAddress> for PioAddress {
152 type Error = IoAddress;
153
154 #[inline]
155 fn try_from(addr: IoAddress) -> Result<Self, Self::Error> {
156 if addr.0 <= std::u16::MAX as u64 {
157 Ok(PioAddress(addr.raw_value() as PioAddressType))
158 } else {
159 Err(addr)
160 }
161 }
162}
163
164impl From<PioAddress> for IoAddress {
165 #[inline]
166 fn from(addr: PioAddress) -> Self {
167 IoAddress(addr.raw_value() as u64)
168 }
169}
170
171#[allow(unused_variables)]
183pub trait DeviceIo: Send + Sync {
184 fn read(&self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {}
186
187 fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]) {}
189
190 fn pio_read(&self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {}
192
193 fn pio_write(&self, base: PioAddress, offset: PioAddress, data: &[u8]) {}
195
196 fn get_assigned_resources(&self) -> DeviceResources {
198 DeviceResources::new()
199 }
200
201 fn get_trapped_io_resources(&self) -> DeviceResources {
206 self.get_assigned_resources()
207 }
208
209 fn as_any(&self) -> &dyn Any;
211}
212
213#[allow(unused_variables)]
221pub trait DeviceIoMut {
222 fn read(&mut self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {}
224
225 fn write(&mut self, base: IoAddress, offset: IoAddress, data: &[u8]) {}
227
228 fn pio_read(&mut self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {}
230
231 fn pio_write(&mut self, base: PioAddress, offset: PioAddress, data: &[u8]) {}
233
234 fn get_assigned_resources(&self) -> DeviceResources {
236 DeviceResources::new()
237 }
238
239 fn get_trapped_io_resources(&self) -> DeviceResources {
244 self.get_assigned_resources()
245 }
246}
247
248impl<T: DeviceIoMut + Send + 'static> DeviceIo for Mutex<T> {
249 fn read(&self, base: IoAddress, offset: IoAddress, data: &mut [u8]) {
250 self.lock().unwrap().read(base, offset, data)
252 }
253
254 fn write(&self, base: IoAddress, offset: IoAddress, data: &[u8]) {
255 self.lock().unwrap().write(base, offset, data)
257 }
258
259 fn pio_read(&self, base: PioAddress, offset: PioAddress, data: &mut [u8]) {
260 self.lock().unwrap().pio_read(base, offset, data)
262 }
263
264 fn pio_write(&self, base: PioAddress, offset: PioAddress, data: &[u8]) {
265 self.lock().unwrap().pio_write(base, offset, data)
267 }
268
269 fn get_assigned_resources(&self) -> DeviceResources {
270 self.lock().unwrap().get_assigned_resources()
272 }
273
274 fn get_trapped_io_resources(&self) -> DeviceResources {
275 self.lock().unwrap().get_trapped_io_resources()
277 }
278
279 fn as_any(&self) -> &dyn Any {
280 self
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use std::convert::TryFrom;
287 use std::sync::Arc;
288
289 use super::*;
290
291 #[derive(Default)]
292 struct MockDevice {
293 data: Mutex<u8>,
294 }
295
296 impl DeviceIo for MockDevice {
297 fn read(&self, _base: IoAddress, _offset: IoAddress, data: &mut [u8]) {
298 data[0] = *self.data.lock().unwrap();
299 }
300
301 fn write(&self, _base: IoAddress, _offset: IoAddress, data: &[u8]) {
302 *self.data.lock().unwrap() = data[0];
303 }
304
305 fn pio_read(&self, _base: PioAddress, _offset: PioAddress, data: &mut [u8]) {
306 data[0] = *self.data.lock().unwrap();
307 }
308
309 fn pio_write(&self, _base: PioAddress, _offset: PioAddress, data: &[u8]) {
310 *self.data.lock().unwrap() = data[0];
311 }
312 fn as_any(&self) -> &dyn Any {
313 self
314 }
315 }
316
317 #[derive(Default)]
318 struct MockDeviceMut {
319 data: u8,
320 }
321
322 impl DeviceIoMut for MockDeviceMut {
323 fn read(&mut self, _base: IoAddress, _offset: IoAddress, data: &mut [u8]) {
324 data[0] = self.data;
325 }
326
327 fn write(&mut self, _base: IoAddress, _offset: IoAddress, data: &[u8]) {
328 self.data = data[0];
329 }
330
331 fn pio_read(&mut self, _base: PioAddress, _offset: PioAddress, data: &mut [u8]) {
332 data[0] = self.data;
333 }
334
335 fn pio_write(&mut self, _base: PioAddress, _offset: PioAddress, data: &[u8]) {
336 self.data = data[0];
337 }
338 }
339
340 fn register_device(device: Arc<dyn DeviceIo>) {
341 device.write(IoAddress(0), IoAddress(0), &[0x10u8]);
342 let mut buf = [0x0u8];
343 device.read(IoAddress(0), IoAddress(0), &mut buf);
344 assert_eq!(buf[0], 0x10);
345
346 {
347 device.pio_write(PioAddress(0), PioAddress(0), &[0x10u8]);
348 let mut buf = [0x0u8];
349 device.pio_read(PioAddress(0), PioAddress(0), &mut buf);
350 assert_eq!(buf[0], 0x10);
351 }
352
353 let resource = DeviceResources::new();
355 assert_eq!(resource, device.get_assigned_resources());
356 assert_eq!(resource, device.get_trapped_io_resources());
357 }
358
359 #[test]
360 fn test_device_io_adapter() {
361 let device = Arc::new(MockDevice::default());
362
363 register_device(device.clone());
364 assert_eq!(*device.data.lock().unwrap(), 0x010);
365 }
366
367 #[test]
368 fn test_device_io_mut_adapter() {
369 let device_mut = Arc::new(Mutex::new(MockDeviceMut::default()));
370
371 register_device(device_mut.clone());
372 assert_eq!(device_mut.lock().unwrap().data, 0x010);
373 }
374
375 #[test]
376 fn test_io_data_struct() {
377 let io_size = IoSize::from(0x1111u64);
378 assert_eq!(io_size.raw_value(), 0x1111u64);
379 assert_eq!(u64::from(io_size), 0x1111u64);
380 assert_eq!(io_size, io_size.clone());
381 let io_size1 = IoSize::from(0x1112u64);
382 assert!(io_size < io_size1);
383
384 let io_addr = IoAddress::from(0x1234u64);
385 assert_eq!(io_addr.raw_value(), 0x1234u64);
386 assert_eq!(u64::from(io_addr), 0x1234u64);
387 assert_eq!(io_addr, io_addr.clone());
388 let io_addr1 = IoAddress::from(0x1235u64);
389 assert!(io_addr < io_addr1);
390 }
391
392 #[test]
393 fn test_pio_data_struct() {
394 let pio_size = PioSize::from(0x1111u16);
395 assert_eq!(pio_size.raw_value(), 0x1111u16);
396 assert_eq!(u16::from(pio_size), 0x1111u16);
397 assert_eq!(pio_size, pio_size.clone());
398 let pio_size1 = PioSize::from(0x1112u16);
399 assert!(pio_size < pio_size1);
400
401 let pio_size = PioSize::try_from(IoSize(0x1111u64)).unwrap();
402 assert_eq!(pio_size.raw_value(), 0x1111u16);
403
404 assert!(PioSize::try_from(IoSize(std::u16::MAX as u64 + 1)).is_err());
405
406 let io_size = IoSize::from(PioSize::from(0x1111u16));
407 assert_eq!(io_size.raw_value(), 0x1111u64);
408
409 let pio_addr = PioAddress::from(0x1234u16);
410 assert_eq!(pio_addr.raw_value(), 0x1234u16);
411 assert_eq!(u16::from(pio_addr), 0x1234u16);
412 assert_eq!(pio_addr, pio_addr.clone());
413 let pio_addr1 = PioAddress::from(0x1235u16);
414 assert!(pio_addr < pio_addr1);
415
416 assert!(PioAddress::try_from(IoAddress::from(0x12_3456u64)).is_err());
417 assert!(PioAddress::try_from(IoAddress::from(0x1234u64)).is_ok());
418 assert_eq!(IoAddress::from(pio_addr).raw_value(), 0x1234u64);
419 }
420}