1#![no_std]
11
12extern crate alloc;
30
31use alloc::vec::Vec;
32use bitflags::bitflags;
33
34pub trait PortOps {
40 unsafe fn read8(&self, port: u16) -> u8;
41 unsafe fn read16(&self, port: u16) -> u16;
42 unsafe fn read32(&self, port: u16) -> u32;
43
44 unsafe fn write8(&self, port: u16, val: u8);
45 unsafe fn write16(&self, port: u16, val: u16);
46 unsafe fn write32(&self, port: u16, val: u32);
47}
48
49const CONFIG_ADDRESS: u16 = 0x0CF8;
50const CONFIG_DATA: u16 = 0x0CFC;
51
52#[derive(Debug, Copy, Clone, PartialEq, Eq)]
53pub enum CSpaceAccessMethod {
54 IO,
60 }
63
64impl CSpaceAccessMethod {
67 pub unsafe fn read8<T: PortOps>(self, ops: &T, loc: Location, offset: u16) -> u8 {
68 let val = self.read32(ops, loc, offset & 0b11111100);
69 ((val >> ((offset as usize & 0b11) << 3)) & 0xFF) as u8
70 }
71
72 pub unsafe fn read16<T: PortOps>(self, ops: &T, loc: Location, offset: u16) -> u16 {
74 let val = self.read32(ops, loc, offset & 0b11111100);
75 ((val >> ((offset as usize & 0b10) << 3)) & 0xFFFF) as u16
76 }
77
78 pub unsafe fn read32<T: PortOps>(self, ops: &T, loc: Location, offset: u16) -> u32 {
80 debug_assert!(
81 (offset & 0b11) == 0,
82 "misaligned PCI configuration dword u32 read"
83 );
84 match self {
85 CSpaceAccessMethod::IO => {
86 ops.write32(
87 CONFIG_ADDRESS,
88 loc.encode() | ((offset as u32) & 0b11111100),
89 );
90 ops.read32(CONFIG_DATA).to_le()
91 } }
96 }
97
98 pub unsafe fn write8<T: PortOps>(self, ops: &T, loc: Location, offset: u16, val: u8) {
99 let old = self.read32(ops, loc, offset);
100 let dest = offset as usize & 0b11 << 3;
101 let mask = (0xFF << dest) as u32;
102 self.write32(
103 ops,
104 loc,
105 offset,
106 ((val as u32) << dest | (old & !mask)).to_le(),
107 );
108 }
109
110 pub unsafe fn write16<T: PortOps>(self, ops: &T, loc: Location, offset: u16, val: u16) {
112 let old = self.read32(ops, loc, offset);
113 let dest = offset as usize & 0b10 << 3;
114 let mask = (0xFFFF << dest) as u32;
115 self.write32(
116 ops,
117 loc,
118 offset,
119 ((val as u32) << dest | (old & !mask)).to_le(),
120 );
121 }
122
123 pub unsafe fn write32<T: PortOps>(self, ops: &T, loc: Location, offset: u16, val: u32) {
126 debug_assert!(
127 (offset & 0b11) == 0,
128 "misaligned PCI configuration dword u32 read"
129 );
130 match self {
131 CSpaceAccessMethod::IO => {
132 ops.write32(CONFIG_ADDRESS, loc.encode() | (offset as u32 & 0b11111100));
133 ops.write32(CONFIG_DATA, val.to_le())
134 } }
139 }
140}
141
142#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
144pub struct Location {
145 pub bus: u8,
146 pub device: u8,
147 pub function: u8,
148}
149
150impl Location {
151 #[inline(always)]
152 fn encode(self) -> u32 {
153 (1 << 31)
154 | ((self.bus as u32) << 16)
155 | (((self.device as u32) & 0b11111) << 11)
156 | (((self.function as u32) & 0b111) << 8)
157 }
158}
159
160#[derive(Debug, Copy, Clone, PartialEq, Eq)]
161pub struct Identifier {
162 pub vendor_id: u16,
163 pub device_id: u16,
164 pub revision_id: u8,
165 pub prog_if: u8,
166 pub class: u8,
167 pub subclass: u8,
168}
169
170bitflags! {
171 pub struct Command: u16 {
172 const IO_SPACE = 0x0001;
173 const MEMORY_SPACE = 0x0002;
174 const BUS_MASTER = 0x0004;
175 const SPECIAL_CYCLES = 0x0008;
176 const MWI_ENABLE = 0x0010;
177 const VGA_PALETTE_SNOOP = 0x0020;
178 const PARITY_ERROR_RESPONSE = 0x0040;
179 const STEPPING_CONTROL = 0x0080;
180 const SERR_ENABLE = 0x0100;
181 const FAST_BACK_TO_BACK_ENABLE = 0x0200;
182 const INTERRUPT_DISABLE = 0x0400;
183 const RESERVED_11 = 0x0800;
184 const RESERVED_12 = 0x1000;
185 const RESERVED_13 = 0x2000;
186 const RESERVED_14 = 0x4000;
187 const RESERVED_15 = 0x8000;
188 }
189}
190
191bitflags! {
192 pub struct Status: u16 {
193 const RESERVED_0 = 0x0001;
194 const RESERVED_1 = 0x0002;
195 const RESERVED_2 = 0x0004;
196 const INTERRUPT_STATUS = 0x0008;
197 const CAPABILITIES_LIST = 0x0010;
198 const MHZ66_CAPABLE = 0x0020;
199 const RESERVED_6 = 0x0040;
200 const FAST_BACK_TO_BACK_CAPABLE = 0x0080;
201 const MASTER_DATA_PARITY_ERROR = 0x0100;
202 const DEVSEL_MEDIUM_TIMING = 0x0200;
203 const DEVSEL_SLOW_TIMING = 0x0400;
204 const SIGNALED_TARGET_ABORT = 0x0800;
205 const RECEIVED_TARGET_ABORT = 0x1000;
206 const RECEIVED_MASTER_ABORT = 0x2000;
207 const SIGNALED_SYSTEM_ERROR = 0x4000;
208 const DETECTED_PARITY_ERROR = 0x8000;
209 }
210}
211
212bitflags! {
213 pub struct BridgeControl: u16 {
214 const PARITY_ERROR_RESPONSE_ENABLE = 0x0001;
215 const SERR_ENABLE = 0x0002;
216 const ISA_ENABLE = 0x0004;
217 const VGA_ENABLE = 0x0008;
218 const RESERVED_4 = 0x0010;
219 const MASTER_ABORT_MODE = 0x0020;
220 const SECONDARY_BUS_RESET = 0x0040;
221 const FAST_BACK_TO_BACK_ENABLE = 0x0080;
222 const PRIMARY_DISCARD_TIMER = 0x0100;
223 const SECONDARY_DISCARD_TIMER = 0x0200;
224 const DISCARD_TIMER_STATUS = 0x0400;
225 const DISCARD_TIMER_SERR_ENABLED = 0x0800;
226 const RESERVED_12 = 0x1000;
227 const RESERVED_13 = 0x2000;
228 const RESERVED_14 = 0x4000;
229 const RESERVED_15 = 0x8000;
230 }
231}
232
233#[derive(Debug, Clone, PartialEq, Eq)]
237pub struct PCIDevice {
238 pub loc: Location,
239 pub id: Identifier,
240 pub command: Command,
241 pub status: Status,
242 pub cache_line_size: u8,
243 pub latency_timer: u8,
244 pub multifunction: bool,
245 pub bist_capable: bool,
246 pub bars: [Option<BAR>; 6],
247 pub kind: DeviceKind,
248 pub pic_interrupt_line: u8,
249 pub interrupt_pin: Option<InterruptPin>,
250 pub cspace_access_method: CSpaceAccessMethod,
251 pub capabilities: Option<Vec<Capability>>,
252}
253
254pub enum PCIScanError {}
255
256#[derive(Debug, Copy, Clone, PartialEq, Eq)]
257pub enum Prefetchable {
258 Yes,
259 No,
260}
261
262#[derive(Debug, Copy, Clone, PartialEq, Eq)]
263pub enum Type {
264 Bits32,
265 Bits64,
266}
267
268#[derive(Debug, Copy, Clone, PartialEq, Eq)]
269pub enum DeviceKind {
270 Device(DeviceDetails),
271 PciBridge(PciBridgeDetails),
272 CardbusBridge(CardbusBridgeDetails),
273 Unknown,
274}
275
276#[derive(Debug, Copy, Clone, PartialEq, Eq)]
277pub struct DeviceDetails {
278 pub cardbus_cis_ptr: u32,
279 pub subsystem_vendor_id: u16,
280 pub subsystem_id: u16,
281 pub expansion_rom_base_addr: u32,
282 pub min_grant: u8,
283 pub max_latency: u8,
284}
285
286#[derive(Debug, Copy, Clone, PartialEq, Eq)]
287pub struct PciBridgeDetails {
288 pub primary_bus: u8,
289 pub secondary_bus: u8,
290 pub subordinate_bus: u8,
291 pub secondary_latency_timer: u8,
292 pub io_base: u32,
293 pub io_limit: u32,
294 pub secondary_status: Status,
295 pub mem_base: u32,
296 pub mem_limit: u32,
297 pub prefetchable_mem_base: u64,
298 pub prefetchable_mem_limit: u64,
299 pub expansion_rom_base_addr: u32,
300 pub bridge_control: BridgeControl,
301}
302
303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
304pub struct CardbusBridgeDetails {
305 pub socket_base_addr: u32,
306 pub secondary_status: Status,
307 pub pci_bus: u8,
308 pub cardbus_bus: u8,
309 pub subordinate_bus: u8,
310 pub cardbus_latency_timer: u8,
311 pub mem_base_0: u32,
312 pub mem_limit_0: u32,
313 pub mem_base_1: u32,
314 pub mem_limit_1: u32,
315 pub io_base_0: u32,
316 pub io_limit_0: u32,
317 pub io_base_1: u32,
318 pub io_limit_1: u32,
319 pub subsystem_device_id: u16,
320 pub subsystem_vendor_id: u16,
321 pub legacy_mode_base_addr: u32,
322 pub bridge_control: BridgeControl,
323}
324
325#[derive(Debug, Copy, Clone, PartialEq, Eq)]
326pub enum InterruptPin {
327 INTA = 1,
328 INTB,
329 INTC,
330 INTD,
331}
332
333bitflags! {
334 pub struct CapabilityMSIMessageControl: u16 {
335 const ADDR64_CAPABLE = 1 << 7;
336 const MULTIPLE_MESSAGE_ENABLE_2 = 1 << 4;
337 const MULTIPLE_MESSAGE_ENABLE_4 = 2 << 4;
338 const MULTIPLE_MESSAGE_ENABLE_8 = 3 << 4;
339 const MULTIPLE_MESSAGE_ENABLE_16 = 4 << 4;
340 const MULTIPLE_MESSAGE_ENABLE_32 = 5 << 4;
341 const MULTIPLE_MESSAGE_CAPABLE_2 = 1 << 1;
342 const MULTIPLE_MESSAGE_CAPABLE_4 = 2 << 1;
343 const MULTIPLE_MESSAGE_CAPABLE_8 = 3 << 1;
344 const MULTIPLE_MESSAGE_CAPABLE_16 = 4 << 1;
345 const MULTIPLE_MESSAGE_CAPABLE_32 = 5 << 1;
346 const ENABLE = 1 << 0;
347 }
348}
349
350#[derive(Debug, Copy, Clone, PartialEq, Eq)]
351pub struct CapabilityMSIData {
352 message_control: CapabilityMSIMessageControl,
353 message_address: u64,
354 message_data: u16,
355}
356
357#[derive(Debug, Copy, Clone, PartialEq, Eq)]
358pub struct CapabilitySATAData {
359 major_revision: u32,
360 minor_revision: u32,
361 bar_offset: u32,
362 bar_location: u32,
363}
364
365#[derive(Debug, Copy, Clone, PartialEq, Eq)]
366pub struct CapabilityPMData {
367 pme_support: u32,
368 d2_support: u32,
369 d1_support: u32,
370 aux_current: u32,
371 dsi: u32,
372 pme_clock: u32,
373 version: u32,
374}
375
376#[derive(Debug, Copy, Clone, PartialEq, Eq)]
377pub struct CapabilityEXPData {
378 interrupt_message_number: u16,
379 slot_implemented: u16,
380 device_port_type: u16,
381 cap_version: u16,
382}
383
384#[derive(Debug, Copy, Clone, PartialEq, Eq)]
385pub enum CapabilityData {
386 PM(CapabilityPMData), AGP, VPD, SLOTID, MSI(CapabilityMSIData), CHSWP, PCIX, HP, VNDR, DBG, CCRC, SHPC, SSVID, AGP3, SECDEV, EXP(CapabilityEXPData), MSIX, SATA(CapabilitySATAData), AF, Unknown(u8),
406}
407
408#[derive(Debug, Copy, Clone, PartialEq, Eq)]
409pub struct Capability {
410 cap_ptr: u16,
411 data: CapabilityData,
412}
413
414#[derive(Debug, Copy, Clone, PartialEq, Eq)]
415pub enum BAR {
416 Memory(u64, u32, Prefetchable, Type),
417 IO(u32, u32),
418}
419
420impl BAR {
421 pub unsafe fn decode<T: PortOps>(
422 ops: &T,
423 loc: Location,
424 am: CSpaceAccessMethod,
425 idx: u16,
426 ) -> (Option<BAR>, usize) {
427 let raw = am.read32(ops, loc, 16 + (idx << 2));
428 am.write32(ops, loc, 16 + (idx << 2), !0);
429 let len_encoded = am.read32(ops, loc, 16 + (idx << 2));
430 am.write32(ops, loc, 16 + (idx << 2), raw);
431 if raw == 0 && len_encoded == 0 {
432 return (None, idx as usize + 1);
433 }
434 if raw & 1 == 0 {
435 let mut bits64 = false;
436 let base: u64 = match (raw & 0b110) >> 1 {
437 0 => (raw & !0xF) as u64,
438 2 => {
439 bits64 = true;
440 ((raw & !0xF) as u64)
441 | ((am.read32(ops, loc, 16 + ((idx + 1) << 2)) as u64) << 32)
442 }
443 _ => {
444 debug_assert!(false, "bad type in memory BAR");
445 return (None, idx as usize + 1);
446 }
447 };
448 let len = !(len_encoded & !0xF).wrapping_add(1);
449 (
450 Some(BAR::Memory(
451 base,
452 len,
453 if raw & 0b1000 == 0 {
454 Prefetchable::No
455 } else {
456 Prefetchable::Yes
457 },
458 if bits64 { Type::Bits64 } else { Type::Bits32 },
459 )),
460 if bits64 { idx + 2 } else { idx + 1 } as usize,
461 )
462 } else {
463 let len = !(len_encoded & !0x3) + 1;
464 (Some(BAR::IO(raw & !0x3, len)), idx as usize + 1)
465 }
466 }
467}
468
469pub struct BusScan<'a, T: PortOps + 'a> {
470 loc: Location,
471 ops: &'a T,
472 am: CSpaceAccessMethod,
473}
474
475impl<'a, T: PortOps> BusScan<'a, T> {
476 fn done(&self) -> bool {
477 if self.loc.bus == 255 && self.loc.device == 31 && self.loc.function == 7 {
478 true
479 } else {
480 false
481 }
482 }
483
484 fn increment(&mut self) {
485 if self.loc.function < 7 {
488 self.loc.function += 1;
489 return;
490 } else {
491 self.loc.function = 0;
492 if self.loc.device < 31 {
493 self.loc.device += 1;
494 return;
495 } else {
496 self.loc.device = 0;
497 if self.loc.bus == 255 {
498 self.loc.device = 31;
499 self.loc.device = 7;
500 } else {
501 self.loc.bus += 1;
502 return;
503 }
504 }
505 }
506 }
507}
508
509impl<'a, T: PortOps> ::core::iter::Iterator for BusScan<'a, T> {
510 type Item = PCIDevice;
511 #[inline]
512 fn next(&mut self) -> Option<PCIDevice> {
513 let mut ret = None;
516 loop {
517 if self.done() {
518 return ret;
519 }
520 unsafe {
521 ret = probe_function(self.ops, self.loc, self.am);
522 }
523 self.increment();
524 if ret.is_some() {
525 return ret;
526 }
527 }
528 }
529}
530
531pub unsafe fn probe_function<T: PortOps>(
532 ops: &T,
533 loc: Location,
534 am: CSpaceAccessMethod,
535) -> Option<PCIDevice> {
536 let vid = am.read16(ops, loc, 0);
538 if vid == 0xFFFF {
539 return None;
540 }
541 let did = am.read16(ops, loc, 2);
542 let command = Command::from_bits_truncate(am.read16(ops, loc, 4));
543 let status = Status::from_bits_truncate(am.read16(ops, loc, 6));
544 let rid = am.read8(ops, loc, 8);
545 let prog_if = am.read8(ops, loc, 9);
546 let subclass = am.read8(ops, loc, 10);
547 let class = am.read8(ops, loc, 11);
548 let id = Identifier {
549 vendor_id: vid,
550 device_id: did,
551 revision_id: rid,
552 prog_if: prog_if,
553 class: class,
554 subclass: subclass,
555 };
556 let cache_line_size = am.read8(ops, loc, 12);
557 let latency_timer = am.read8(ops, loc, 13);
558 let bist_capable = am.read8(ops, loc, 15) & (1 << 7) != 0;
559 let hdrty_mf = am.read8(ops, loc, 14);
560 let hdrty = hdrty_mf & !(1 << 7);
561 let mf = hdrty_mf & (1 << 7) != 0;
562 let pic_interrupt_line = am.read8(ops, loc, 0x3C);
563 let interrupt_pin = match am.read8(ops, loc, 0x3D) {
564 1 => Some(InterruptPin::INTA),
565 2 => Some(InterruptPin::INTB),
566 3 => Some(InterruptPin::INTC),
567 4 => Some(InterruptPin::INTD),
568 _ => None,
569 };
570 let kind;
571 let max;
572
573 match hdrty {
574 0 => {
575 max = 6;
576 kind = DeviceKind::Device(DeviceDetails {
577 cardbus_cis_ptr: am.read32(ops, loc, 0x28),
578 subsystem_vendor_id: am.read16(ops, loc, 0x2C),
579 subsystem_id: am.read16(ops, loc, 0x2E),
580 expansion_rom_base_addr: am.read32(ops, loc, 0x30),
581 min_grant: am.read8(ops, loc, 0x3E),
582 max_latency: am.read8(ops, loc, 0x3F),
583 });
584 }
585 1 => {
586 max = 2;
587 kind = DeviceKind::PciBridge(PciBridgeDetails {
588 primary_bus: am.read8(ops, loc, 0x18),
589 secondary_bus: am.read8(ops, loc, 0x19),
590 subordinate_bus: am.read8(ops, loc, 0x1a),
591 secondary_latency_timer: am.read8(ops, loc, 0x1b),
592 secondary_status: Status::from_bits_truncate(am.read16(ops, loc, 0x1e)),
593 io_base: (am.read8(ops, loc, 0x1c) as u32 & 0xF0) << 8
594 | (am.read16(ops, loc, 0x30) as u32) << 16,
595 io_limit: 0xFFF
596 | (am.read8(ops, loc, 0x1d) as u32 & 0xF0) << 8
597 | (am.read16(ops, loc, 0x32) as u32) << 16,
598 mem_base: (am.read16(ops, loc, 0x20) as u32 & 0xFFF0) << 16,
599 mem_limit: 0xFFFFF | (am.read16(ops, loc, 0x22) as u32 & 0xFFF0) << 16,
600 prefetchable_mem_base: (am.read16(ops, loc, 0x24) as u64 & 0xFFF0) << 16
601 | am.read32(ops, loc, 0x28) as u64,
602 prefetchable_mem_limit: 0xFFFFF
603 | (am.read16(ops, loc, 0x26) as u64 & 0xFFF0) << 16
604 | am.read32(ops, loc, 0x2c) as u64,
605 expansion_rom_base_addr: am.read32(ops, loc, 0x38),
606 bridge_control: BridgeControl::from_bits_truncate(am.read16(ops, loc, 0x3e)),
607 });
608 }
609 2 => {
610 max = 0;
611 kind = DeviceKind::CardbusBridge(CardbusBridgeDetails {
612 socket_base_addr: am.read32(ops, loc, 0x10),
613 secondary_status: Status::from_bits_truncate(am.read16(ops, loc, 0x16)),
614 pci_bus: am.read8(ops, loc, 0x18),
615 cardbus_bus: am.read8(ops, loc, 0x19),
616 subordinate_bus: am.read8(ops, loc, 0x1a),
617 cardbus_latency_timer: am.read8(ops, loc, 0x1b),
618 mem_base_0: am.read32(ops, loc, 0x1c),
619 mem_limit_0: am.read32(ops, loc, 0x20),
620 mem_base_1: am.read32(ops, loc, 0x24),
621 mem_limit_1: am.read32(ops, loc, 0x28),
622 io_base_0: am.read32(ops, loc, 0x2c),
623 io_limit_0: am.read32(ops, loc, 0x30),
624 io_base_1: am.read32(ops, loc, 0x34),
625 io_limit_1: am.read32(ops, loc, 0x38),
626 bridge_control: BridgeControl::from_bits_truncate(am.read16(ops, loc, 0x3e)),
627 subsystem_device_id: am.read16(ops, loc, 0x40),
628 subsystem_vendor_id: am.read16(ops, loc, 0x42),
629 legacy_mode_base_addr: am.read32(ops, loc, 0x44),
630 });
631 }
632 _ => {
633 max = 0;
634 kind = DeviceKind::Unknown;
635 debug_assert!(
636 false,
637 "pci: unknown device header type {} for {:?} {:?}",
638 hdrty, loc, id
639 );
640 }
641 };
642
643 let mut capabilities = None;
644 if status.contains(Status::CAPABILITIES_LIST) {
645 let mut caps = Vec::new();
646 let mut cap_pointer = am.read8(ops, loc, 0x34) as u16;
648 while cap_pointer > 0 {
649 let cap_id = am.read8(ops, loc, cap_pointer);
650 let data = match cap_id {
651 0x01 => {
652 let cap = am.read32(ops, loc, cap_pointer + 0x4);
653 CapabilityData::PM(CapabilityPMData {
654 pme_support: cap >> 27,
655 d2_support: (cap >> 26) & 0x1,
656 d1_support: (cap >> 25) & 0x1,
657 aux_current: (cap >> 22) & 0x7,
658 dsi: (cap >> 21) & 0x1,
659 pme_clock: (cap >> 19) & 0x1,
660 version: (cap >> 16) & 0x7,
661 })
662 }
663 0x02 => CapabilityData::AGP,
664 0x03 => CapabilityData::VPD,
665 0x04 => CapabilityData::SLOTID,
666 0x05 => {
667 let message_control = CapabilityMSIMessageControl::from_bits_truncate(
668 am.read16(ops, loc, cap_pointer + 0x02),
669 );
670 let (addr, data) =
671 if message_control.contains(CapabilityMSIMessageControl::ADDR64_CAPABLE) {
672 let lo = am.read32(ops, loc, cap_pointer + 0x04) as u64;
674 let hi = am.read32(ops, loc, cap_pointer + 0x08) as u64;
675 let data = am.read16(ops, loc, cap_pointer + 0x0C);
676 ((hi << 32) | lo, data)
677 } else {
678 let addr = am.read32(ops, loc, cap_pointer + 0x04) as u64;
680 let data = am.read16(ops, loc, cap_pointer + 0x0C);
681 (addr, data)
682 };
683 CapabilityData::MSI(CapabilityMSIData {
684 message_control: message_control,
685 message_address: addr,
686 message_data: data,
687 })
688 }
689 0x10 => {
690 let cap = am.read16(ops, loc, cap_pointer + 0x2);
691 CapabilityData::EXP(CapabilityEXPData {
692 interrupt_message_number: (cap >> 9) & 0b11111,
693 slot_implemented: (cap >> 8) & 0x1,
694 device_port_type: (cap >> 4) & 0xf,
695 cap_version: cap & 0xf,
696 })
697 }
698 0x11 => CapabilityData::MSIX,
699 0x12 => {
700 let sata_cr0 = am.read32(ops, loc, cap_pointer);
701 let sata_cr1 = am.read32(ops, loc, cap_pointer + 0x4);
702 CapabilityData::SATA(CapabilitySATAData {
703 major_revision: (sata_cr0 >> 20) & 0xf,
704 minor_revision: (sata_cr0 >> 16) & 0xf,
705 bar_offset: (sata_cr1 >> 4) & 0xfffff,
706 bar_location: sata_cr1 & 0xf,
707 })
708 }
709 _ => CapabilityData::Unknown(cap_id),
710 };
711 caps.push(Capability {
712 cap_ptr: cap_pointer,
713 data: data,
714 });
715 cap_pointer = am.read8(ops, loc, cap_pointer + 1) as u16;
716 }
717 capabilities = Some(caps);
718 }
719
720 let mut bars = [None, None, None, None, None, None];
721 let mut i = 0;
722 while i < max {
723 let (bar, next) = BAR::decode(ops, loc, am, i as u16);
724 bars[i] = bar;
725 i = next;
726 }
727
728 Some(PCIDevice {
729 loc: loc,
730 id: id,
731 command: command,
732 status: status,
733 cache_line_size: cache_line_size,
734 latency_timer: latency_timer,
735 multifunction: mf,
736 bist_capable: bist_capable,
737 bars: bars,
738 kind: kind,
739 pic_interrupt_line: pic_interrupt_line,
740 interrupt_pin: interrupt_pin,
741 cspace_access_method: am,
742 capabilities: capabilities,
743 })
744}
745
746pub unsafe fn scan_bus<'a, T: PortOps>(ops: &'a T, am: CSpaceAccessMethod) -> BusScan<'a, T> {
747 BusScan {
748 loc: Location {
749 bus: 0,
750 device: 0,
751 function: 0,
752 },
753 ops: ops,
754 am: am,
755 }
756}