Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
drivers
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MLA98
drivers
Commits
452c586b
Unverified
Commit
452c586b
authored
Mar 01, 2018
by
Jeremy Soller
Committed by
GitHub
Mar 01, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #28 from dlrobertson/update_pci_parsing
Allow PCI Config space parsing to handle types
parents
42adde58
4d349192
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
575 additions
and
202 deletions
+575
-202
Cargo.lock
Cargo.lock
+2
-0
pcid/Cargo.toml
pcid/Cargo.toml
+2
-0
pcid/src/main.rs
pcid/src/main.rs
+136
-134
pcid/src/pci/bar.rs
pcid/src/pci/bar.rs
+22
-1
pcid/src/pci/class.rs
pcid/src/pci/class.rs
+28
-1
pcid/src/pci/func.rs
pcid/src/pci/func.rs
+21
-20
pcid/src/pci/header.rs
pcid/src/pci/header.rs
+354
-36
pcid/src/pci/mod.rs
pcid/src/pci/mod.rs
+10
-10
No files found.
Cargo.lock
View file @
452c586b
...
...
@@ -342,6 +342,8 @@ dependencies = [
name = "pcid"
version = "0.1.0"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
...
...
pcid/Cargo.toml
View file @
452c586b
...
...
@@ -3,6 +3,8 @@ name = "pcid"
version
=
"0.1.0"
[dependencies]
bitflags
=
"1.0"
byteorder
=
"1.2"
redox_syscall
=
"0.1"
serde
=
"1.0"
serde_derive
=
"1.0"
...
...
pcid/src/main.rs
View file @
452c586b
#![deny(warnings)]
#![feature(asm)]
#![feature(iterator_step_by)]
#[macro_use]
extern
crate
bitflags
;
extern
crate
byteorder
;
#[macro_use]
extern
crate
serde_derive
;
extern
crate
syscall
;
extern
crate
toml
;
...
...
@@ -12,11 +15,136 @@ use std::process::Command;
use
syscall
::
iopl
;
use
config
::
Config
;
use
pci
::{
Pci
,
Pci
Bar
,
PciClass
};
use
pci
::{
Pci
,
Pci
Class
,
PciHeader
,
PciHeaderError
,
PciHeaderType
};
mod
config
;
mod
pci
;
fn
handle_parsed_header
(
config
:
&
Config
,
pci
:
&
Pci
,
bus_num
:
u8
,
dev_num
:
u8
,
func_num
:
u8
,
header
:
PciHeader
)
{
let
raw_class
:
u8
=
header
.class
()
.into
();
let
mut
string
=
format!
(
"PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}"
,
bus_num
,
dev_num
,
func_num
,
header
.vendor_id
(),
header
.device_id
(),
raw_class
,
header
.subclass
(),
header
.interface
(),
header
.revision
(),
header
.class
());
match
header
.class
()
{
PciClass
::
Storage
=>
match
header
.subclass
()
{
0x01
=>
{
string
.push_str
(
" IDE"
);
},
0x06
=>
{
string
.push_str
(
" SATA"
);
},
_
=>
()
},
PciClass
::
SerialBus
=>
match
header
.subclass
()
{
0x03
=>
match
header
.interface
()
{
0x00
=>
{
string
.push_str
(
" UHCI"
);
},
0x10
=>
{
string
.push_str
(
" OHCI"
);
},
0x20
=>
{
string
.push_str
(
" EHCI"
);
},
0x30
=>
{
string
.push_str
(
" XHCI"
);
},
_
=>
()
},
_
=>
()
},
_
=>
()
}
for
(
i
,
bar
)
in
header
.bars
()
.iter
()
.enumerate
()
{
if
!
bar
.is_none
()
{
string
.push_str
(
&
format!
(
" {}={}"
,
i
,
bar
));
}
}
string
.push
(
'\n'
);
print!
(
"{}"
,
string
);
for
driver
in
config
.drivers
.iter
()
{
if
let
Some
(
class
)
=
driver
.class
{
if
class
!=
raw_class
{
continue
;
}
}
if
let
Some
(
subclass
)
=
driver
.subclass
{
if
subclass
!=
header
.subclass
()
{
continue
;
}
}
if
let
Some
(
interface
)
=
driver
.interface
{
if
interface
!=
header
.interface
()
{
continue
;
}
}
if
let
Some
(
vendor
)
=
driver
.vendor
{
if
vendor
!=
header
.vendor_id
()
{
continue
;
}
}
if
let
Some
(
device
)
=
driver
.device
{
if
device
!=
header
.device_id
()
{
continue
;
}
}
if
let
Some
(
ref
device_id_range
)
=
driver
.device_id_range
{
if
header
.device_id
()
<
device_id_range
.start
||
device_id_range
.end
<=
header
.device_id
()
{
continue
;
}
}
if
let
Some
(
ref
args
)
=
driver
.command
{
// Enable bus mastering, memory space, and I/O space
unsafe
{
let
cmd
=
pci
.read
(
bus_num
,
dev_num
,
func_num
,
0x04
);
println!
(
"PCI CMD: {:>02X}"
,
cmd
);
pci
.write
(
bus_num
,
dev_num
,
func_num
,
0x04
,
cmd
|
7
);
}
// TODO: find a better way to pass the header data down to the
// device driver, making passing the capabilities list etc
// posible.
let
mut
args
=
args
.iter
();
if
let
Some
(
program
)
=
args
.next
()
{
let
mut
command
=
Command
::
new
(
program
);
for
arg
in
args
{
let
arg
=
match
arg
.as_str
()
{
"$BUS"
=>
format!
(
"{:>02X}"
,
bus_num
),
"$DEV"
=>
format!
(
"{:>02X}"
,
dev_num
),
"$FUNC"
=>
format!
(
"{:>02X}"
,
func_num
),
"$NAME"
=>
format!
(
"pci-{:>02X}.{:>02X}.{:>02X}"
,
bus_num
,
dev_num
,
func_num
),
"$BAR0"
=>
format!
(
"{}"
,
header
.get_bar
(
0
)),
"$BAR1"
=>
format!
(
"{}"
,
header
.get_bar
(
1
)),
"$BAR2"
if
header
.header_type
()
==
PciHeaderType
::
GENERAL
=>
format!
(
"{}"
,
header
.get_bar
(
2
)),
"$BAR3"
if
header
.header_type
()
==
PciHeaderType
::
GENERAL
=>
format!
(
"{}"
,
header
.get_bar
(
2
)),
"$BAR4"
if
header
.header_type
()
==
PciHeaderType
::
GENERAL
=>
format!
(
"{}"
,
header
.get_bar
(
2
)),
"$BAR5"
if
header
.header_type
()
==
PciHeaderType
::
GENERAL
=>
format!
(
"{}"
,
header
.get_bar
(
2
)),
"$IRQ"
=>
format!
(
"{}"
,
header
.interrupt_line
()),
"$VENID"
=>
format!
(
"{:>04X}"
,
header
.vendor_id
()),
"$DEVID"
=>
format!
(
"{:>04X}"
,
header
.device_id
()),
_
=>
arg
.clone
()
};
command
.arg
(
&
arg
);
}
println!
(
"PCID SPAWN {:?}"
,
command
);
match
command
.spawn
()
{
Ok
(
mut
child
)
=>
match
child
.wait
()
{
Ok
(
_
status
)
=>
(),
//println!("pcid: waited for {}: {:?}", line, status.code()),
Err
(
err
)
=>
println!
(
"pcid: failed to wait for {:?}: {}"
,
command
,
err
)
},
Err
(
err
)
=>
println!
(
"pcid: failed to execute {:?}: {}"
,
command
,
err
)
}
}
}
}
}
fn
main
()
{
let
mut
config
=
Config
::
default
();
...
...
@@ -38,140 +166,14 @@ fn main() {
for
bus
in
pci
.buses
()
{
for
dev
in
bus
.devs
()
{
for
func
in
dev
.funcs
()
{
if
let
Some
(
header
)
=
func
.header
()
{
let
pci_class
=
PciClass
::
from
(
header
.class
);
let
mut
string
=
unsafe
{
format!
(
"PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}"
,
bus
.num
,
dev
.num
,
func
.num
,
header
.vendor_id
,
header
.device_id
,
header
.class
,
header
.subclass
,
header
.interface
,
header
.revision
,
pci_class
)
};
match
pci_class
{
PciClass
::
Storage
=>
match
header
.subclass
{
0x01
=>
{
string
.push_str
(
" IDE"
);
},
0x06
=>
{
string
.push_str
(
" SATA"
);
},
_
=>
()
},
PciClass
::
SerialBus
=>
match
header
.subclass
{
0x03
=>
match
header
.interface
{
0x00
=>
{
string
.push_str
(
" UHCI"
);
},
0x10
=>
{
string
.push_str
(
" OHCI"
);
},
0x20
=>
{
string
.push_str
(
" EHCI"
);
},
0x30
=>
{
string
.push_str
(
" XHCI"
);
},
_
=>
()
},
_
=>
()
},
_
=>
()
}
unsafe
{
for
i
in
0
..
header
.bars
.len
()
{
match
PciBar
::
from
(
header
.bars
[
i
])
{
PciBar
::
None
=>
(),
PciBar
::
Memory
(
address
)
=>
string
.push_str
(
&
format!
(
" {}={:>08X}"
,
i
,
address
)),
PciBar
::
Port
(
address
)
=>
string
.push_str
(
&
format!
(
" {}={:>04X}"
,
i
,
address
))
}
}
let
func_num
=
func
.num
;
match
PciHeader
::
from_reader
(
func
)
{
Ok
(
header
)
=>
{
handle_parsed_header
(
&
config
,
&
pci
,
bus
.num
,
dev
.num
,
func_num
,
header
);
}
string
.push
(
'\n'
);
print!
(
"{}"
,
string
);
for
driver
in
config
.drivers
.iter
()
{
if
let
Some
(
class
)
=
driver
.class
{
if
class
!=
header
.class
{
continue
;
}
}
if
let
Some
(
subclass
)
=
driver
.subclass
{
if
subclass
!=
header
.subclass
{
continue
;
}
}
if
let
Some
(
interface
)
=
driver
.interface
{
if
interface
!=
header
.interface
{
continue
;
}
}
if
let
Some
(
vendor
)
=
driver
.vendor
{
if
vendor
!=
header
.vendor_id
{
continue
;
}
}
if
let
Some
(
device
)
=
driver
.device
{
if
device
!=
header
.device_id
{
continue
;
}
}
if
let
Some
(
ref
device_id_range
)
=
driver
.device_id_range
{
if
header
.device_id
<
device_id_range
.start
||
device_id_range
.end
<=
header
.device_id
{
continue
;
}
}
if
let
Some
(
ref
args
)
=
driver
.command
{
// Enable bus mastering, memory space, and I/O space
unsafe
{
let
cmd
=
pci
.read
(
bus
.num
,
dev
.num
,
func
.num
,
0x04
);
println!
(
"PCI CMD: {:>02X}"
,
cmd
);
pci
.write
(
bus
.num
,
dev
.num
,
func
.num
,
0x04
,
cmd
|
7
);
}
let
mut
args
=
args
.iter
();
if
let
Some
(
program
)
=
args
.next
()
{
let
mut
command
=
Command
::
new
(
program
);
for
arg
in
args
{
let
bar_arg
=
|
i
|
->
String
{
match
PciBar
::
from
(
header
.bars
[
i
])
{
PciBar
::
None
=>
String
::
new
(),
PciBar
::
Memory
(
address
)
=>
format!
(
"{:>08X}"
,
address
),
PciBar
::
Port
(
address
)
=>
format!
(
"{:>04X}"
,
address
)
}
};
let
arg
=
unsafe
{
match
arg
.as_str
()
{
"$BUS"
=>
format!
(
"{:>02X}"
,
bus
.num
),
"$DEV"
=>
format!
(
"{:>02X}"
,
dev
.num
),
"$FUNC"
=>
format!
(
"{:>02X}"
,
func
.num
),
"$NAME"
=>
format!
(
"pci-{:>02X}.{:>02X}.{:>02X}"
,
bus
.num
,
dev
.num
,
func
.num
),
"$BAR0"
=>
bar_arg
(
0
),
"$BAR1"
=>
bar_arg
(
1
),
"$BAR2"
=>
bar_arg
(
2
),
"$BAR3"
=>
bar_arg
(
3
),
"$BAR4"
=>
bar_arg
(
4
),
"$BAR5"
=>
bar_arg
(
5
),
"$IRQ"
=>
format!
(
"{}"
,
header
.interrupt_line
),
"$VENID"
=>
format!
(
"{:>04X}"
,
header
.vendor_id
),
"$DEVID"
=>
format!
(
"{:>04X}"
,
header
.device_id
),
"$SUBSYSID"
=>
format!
(
"{:>04X}"
,
header
.subsystem_id
),
_
=>
arg
.clone
()
}
};
command
.arg
(
&
arg
);
}
//println!("PCID SPAWN {:?}", command);
match
command
.spawn
()
{
Ok
(
mut
child
)
=>
match
child
.wait
()
{
Ok
(
_
status
)
=>
(),
//println!("pcid: waited for {}: {:?}", line, status.code()),
Err
(
err
)
=>
println!
(
"pcid: failed to wait for {:?}: {}"
,
command
,
err
)
},
Err
(
err
)
=>
println!
(
"pcid: failed to execute {:?}: {}"
,
command
,
err
)
}
}
}
Err
(
PciHeaderError
::
NoDevice
)
=>
{},
Err
(
PciHeaderError
::
UnknownHeaderType
(
id
))
=>
{
println!
(
"pcid: unknown header type: {}"
,
id
);
}
}
}
...
...
pcid/src/pci/bar.rs
View file @
452c586b
#[derive(Debug)]
use
std
::
fmt
;
#[derive(Clone,
Copy,
Debug,
PartialEq)]
pub
enum
PciBar
{
None
,
Memory
(
u32
),
Port
(
u16
)
}
impl
PciBar
{
pub
fn
is_none
(
&
self
)
->
bool
{
match
self
{
&
PciBar
::
None
=>
true
,
_
=>
false
,
}
}
}
impl
From
<
u32
>
for
PciBar
{
fn
from
(
bar
:
u32
)
->
Self
{
if
bar
&
0xFFFFFFFC
==
0
{
...
...
@@ -16,3 +27,13 @@ impl From<u32> for PciBar {
}
}
}
impl
fmt
::
Display
for
PciBar
{
fn
fmt
(
&
self
,
f
:
&
mut
fmt
::
Formatter
)
->
fmt
::
Result
{
match
self
{
&
PciBar
::
Memory
(
address
)
=>
write!
(
f
,
"{:>08X}"
,
address
),
&
PciBar
::
Port
(
address
)
=>
write!
(
f
,
"{:>04X}"
,
address
),
&
PciBar
::
None
=>
write!
(
f
,
"None"
)
}
}
}
pcid/src/pci/class.rs
View file @
452c586b
#[derive(
Debug
)]
#[derive(
Clone,
Copy,
Debug,
PartialEq
)]
pub
enum
PciClass
{
Legacy
,
Storage
,
...
...
@@ -48,3 +48,30 @@ impl From<u8> for PciClass {
}
}
}
impl
Into
<
u8
>
for
PciClass
{
fn
into
(
self
)
->
u8
{
match
self
{
PciClass
::
Legacy
=>
0x00
,
PciClass
::
Storage
=>
0x01
,
PciClass
::
Network
=>
0x02
,
PciClass
::
Display
=>
0x03
,
PciClass
::
Multimedia
=>
0x04
,
PciClass
::
Memory
=>
0x05
,
PciClass
::
Bridge
=>
0x06
,
PciClass
::
SimpleComms
=>
0x07
,
PciClass
::
Peripheral
=>
0x08
,
PciClass
::
Input
=>
0x09
,
PciClass
::
Docking
=>
0x0A
,
PciClass
::
Processor
=>
0x0B
,
PciClass
::
SerialBus
=>
0x0C
,
PciClass
::
Wireless
=>
0x0D
,
PciClass
::
IntelligentIo
=>
0x0E
,
PciClass
::
SatelliteComms
=>
0x0F
,
PciClass
::
Cryptography
=>
0x10
,
PciClass
::
SignalProc
=>
0x11
,
PciClass
::
Unknown
=>
0xFF
,
PciClass
::
Reserved
(
reserved
)
=>
reserved
}
}
}
pcid/src/pci/func.rs
View file @
452c586b
use
std
::
ops
::
DerefMut
;
use
byteorder
::{
LittleEndian
,
ByteOrder
}
;
use
super
::{
PciDev
,
PciHeader
};
use
super
::
PciDev
;
pub
trait
ConfigReader
{
unsafe
fn
read_range
(
&
self
,
offset
:
u8
,
len
:
u8
)
->
Vec
<
u8
>
{
assert
!
(
len
>
3
&&
len
%
4
==
0
);
let
mut
ret
=
Vec
::
with_capacity
(
len
as
usize
);
let
results
=
(
offset
..
offset
+
len
)
.step_by
(
4
)
.fold
(
Vec
::
new
(),
|
mut
acc
,
offset
|
{
let
val
=
self
.read_u32
(
offset
);
acc
.push
(
val
);
acc
});
ret
.set_len
(
len
as
usize
);
LittleEndian
::
write_u32_into
(
&*
results
,
&
mut
ret
);
ret
}
unsafe
fn
read_u32
(
&
self
,
offset
:
u8
)
->
u32
;
}
pub
struct
PciFunc
<
'pci
>
{
pub
dev
:
&
'pci
PciDev
<
'pci
>
,
pub
num
:
u8
}
impl
<
'pci
>
PciFunc
<
'pci
>
{
pub
fn
header
(
&
self
)
->
Option
<
PciHeader
>
{
if
unsafe
{
self
.read
(
0
)
}
!=
0xFFFFFFFF
{
let
mut
header
=
PciHeader
::
default
();
{
let
dwords
=
header
.deref_mut
();
dwords
.iter_mut
()
.fold
(
0u
size
,
|
offset
,
dword
|
{
*
dword
=
unsafe
{
self
.read
(
offset
as
u8
)
};
offset
+
4
});
}
Some
(
header
)
}
else
{
None
}
}
pub
unsafe
fn
read
(
&
self
,
offset
:
u8
)
->
u32
{
impl
<
'pci
>
ConfigReader
for
PciFunc
<
'pci
>
{
unsafe
fn
read_u32
(
&
self
,
offset
:
u8
)
->
u32
{
self
.dev
.read
(
self
.num
,
offset
)
}
}
pcid/src/pci/header.rs
View file @
452c586b
use
std
::
ops
::{
Deref
,
DerefMut
};
use
std
::{
slice
,
mem
};
#[derive(Default)]
#[repr(packed)]
pub
struct
PciHeader
{
pub
vendor_id
:
u16
,
pub
device_id
:
u16
,
pub
command
:
u16
,
pub
status
:
u16
,
pub
revision
:
u8
,
pub
interface
:
u8
,
pub
subclass
:
u8
,
pub
class
:
u8
,
pub
cache_line_size
:
u8
,
pub
latency_timer
:
u8
,
pub
header_type
:
u8
,
pub
bist
:
u8
,
pub
bars
:
[
u32
;
6
],
pub
cardbus_cis_ptr
:
u32
,
pub
subsystem_vendor_id
:
u16
,
pub
subsystem_id
:
u16
,
pub
expansion_rom_bar
:
u32
,
pub
capabilities
:
u8
,
pub
reserved
:
[
u8
;
7
],
pub
interrupt_line
:
u8
,
pub
interrupt_pin
:
u8
,
pub
min_grant
:
u8
,
pub
max_latency
:
u8
use
byteorder
::{
LittleEndian
,
ByteOrder
};
use
super
::
func
::
ConfigReader
;
use
super
::
class
::
PciClass
;
use
super
::
bar
::
PciBar
;
#[derive(Debug,
PartialEq)]
pub
enum
PciHeaderError
{
NoDevice
,
UnknownHeaderType
(
u8
)
}
bitflags!
{
/// Flags found in the status register of a PCI device
pub
struct
PciHeaderType
:
u8
{
/// A general PCI device (Type 0x01).
const
GENERAL
=
0b00000000
;
/// A PCI-to-PCI bridge device (Type 0x01).
const
PCITOPCI
=
0b00000001
;
/// A PCI-to-PCI bridge device (Type 0x02).
const
CARDBUSBRIDGE
=
0b00000010
;
/// A multifunction device.
const
MULTIFUNCTION
=
0b01000000
;
/// Mask used for fetching the header type.
const
HEADER_TYPE
=
0b00000011
;
}
}
impl
Deref
for
PciHeader
{
type
Target
=
[
u32
];
fn
deref
(
&
self
)
->
&
[
u32
]
{
unsafe
{
slice
::
from_raw_parts
(
self
as
*
const
PciHeader
as
*
const
u32
,
mem
::
size_of
::
<
PciHeader
>
()
/
4
)
as
&
[
u32
]
}
#[derive(Debug,
PartialEq)]
pub
enum
PciHeader
{
General
{
vendor_id
:
u16
,
device_id
:
u16
,
command
:
u16
,
status
:
u16
,
revision
:
u8
,
interface
:
u8
,
subclass
:
u8
,
class
:
PciClass
,
cache_line_size
:
u8
,
latency_timer
:
u8
,
header_type
:
PciHeaderType
,
bist
:
u8
,
bars
:
[
PciBar
;
6
],
cardbus_cis_ptr
:
u32
,
subsystem_vendor_id
:
u16
,
subsystem_id
:
u16
,
expansion_rom_bar
:
u32
,
cap_pointer
:
u8
,
interrupt_line
:
u8
,
interrupt_pin
:
u8
,
min_grant
:
u8
,
max_latency
:
u8
},
PciToPci
{
vendor_id
:
u16
,
device_id
:
u16
,
command
:
u16
,
status
:
u16
,
revision
:
u8
,
interface
:
u8
,
subclass
:
u8
,
class
:
PciClass
,
cache_line_size
:
u8
,
latency_timer
:
u8
,
header_type
:
PciHeaderType
,
bist
:
u8
,
bars
:
[
PciBar
;
2
],
primary_bus_num
:
u8
,
secondary_bus_num
:
u8
,
subordinate_bus_num
:
u8
,
secondary_latency_timer
:
u8
,
io_base
:
u8
,
io_limit
:
u8
,
secondary_status
:
u16
,
mem_base
:
u16
,
mem_limit
:
u16
,
prefetch_base
:
u16
,
prefetch_limit
:
u16
,
prefetch_base_upper
:
u32
,
prefetch_limit_upper
:
u32
,
io_base_upper
:
u16
,
io_limit_upper
:
u16
,
cap_pointer
:
u8
,
expansion_rom
:
u32
,
interrupt_line
:
u8
,
interrupt_pin
:
u8
,
bridge_control
:
u16
}
}
impl
DerefMut
for
PciHeader
{
fn
deref_mut
(
&
mut
self
)
->
&
mut
[
u32
]
{
unsafe
{
slice
::
from_raw_parts_mut
(
self
as
*
mut
PciHeader
as
*
mut
u32
,
mem
::
size_of
::
<
PciHeader
>
()
/
4
)
as
&
mut
[
u32
]
}
impl
PciHeader
{
/// Parse the bytes found in the Configuration Space of the PCI device into
/// a more usable PciHeader.
pub
fn
from_reader
<
T
:
ConfigReader
>
(
reader
:
T
)
->
Result
<
PciHeader
,
PciHeaderError
>
{
if
unsafe
{
reader
.read_u32
(
0
)
}
!=
0xffffffff
{
// Read the initial 16 bytes and set variables used by all header types.
let
bytes
=
unsafe
{
reader
.read_range
(
0
,
16
)
};
let
vendor_id
=
LittleEndian
::
read_u16
(
&
bytes
[
0
..
2
]);
let
device_id
=
LittleEndian
::
read_u16
(
&
bytes
[
2
..
4
]);
let
command
=
LittleEndian
::
read_u16
(
&
bytes
[
4
..
6
]);
let
status
=
LittleEndian
::
read_u16
(
&
bytes
[
6
..
8
]);
let
revision
=
bytes
[
8
];
let
interface
=
bytes
[
9
];
let
subclass
=
bytes
[
10
];
let
class
=
PciClass
::
from
(
bytes
[
11
]);
let
cache_line_size
=
bytes
[
12
];
let
latency_timer
=
bytes
[
13
];
let
header_type
=
PciHeaderType
::
from_bits_truncate
(
bytes
[
14
]);
let
bist
=
bytes
[
15
];
match
header_type
&
PciHeaderType
::
HEADER_TYPE
{
PciHeaderType
::
GENERAL
=>
{
let
bytes
=
unsafe
{
reader
.read_range
(
16
,
48
)
};
let
bars
=
[
PciBar
::
from
(
LittleEndian
::
read_u32
(
&
bytes
[
0
..
4
])),
PciBar
::
from
(
LittleEndian
::
read_u32
(
&
bytes
[
4
..
8
])),
PciBar
::
from
(
LittleEndian
::
read_u32
(
&
bytes
[
8
..
12
])),
PciBar
::
from
(
LittleEndian
::
read_u32
(
&
bytes
[
12
..
16
])),
PciBar
::
from
(
LittleEndian
::
read_u32
(
&
bytes
[
16
..
20
])),
PciBar
::
from
(
LittleEndian
::
read_u32
(
&
bytes
[
20
..
24
])),
];
let
cardbus_cis_ptr
=
LittleEndian
::
read_u32
(
&
bytes
[
24
..
28
]);
let
subsystem_vendor_id
=
LittleEndian
::
read_u16
(
&
bytes
[
28
..
30
]);
let
subsystem_id
=
LittleEndian
::
read_u16
(
&
bytes
[
30
..
32
]);
let
expansion_rom_bar
=
LittleEndian
::
read_u32
(
&
bytes
[
32
..
36
]);
// TODO: Parse out the capabilities list.
let
cap_pointer
=
bytes
[
36
];
let
interrupt_line
=
bytes
[
44
];
let
interrupt_pin
=
bytes
[
45
];
let
min_grant
=
bytes
[
46
];
let
max_latency
=
bytes
[
47
];
Ok
(
PciHeader
::
General
{
vendor_id
,
device_id
,
command
,
status
,
revision
,
interface
,
subclass
,
class
,
cache_line_size
,
latency_timer
,
header_type
,