summaryrefslogtreecommitdiff
path: root/src/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pci.c')
-rw-r--r--src/pci.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/pci.c b/src/pci.c
new file mode 100644
index 0000000..fce20df
--- /dev/null
+++ b/src/pci.c
@@ -0,0 +1,48 @@
+#include "pci.h"
+
+#include "string.h"
+
+void pci_controller_init( pci_controller_t *controller )
+{
+ memset( controller, 0, sizeof( pci_controller_t ) );
+
+ port32_init( &controller->command_port, 0xCF8 );
+ port32_init( &controller->data_port, 0xCFC );
+}
+
+static uint32_t compute_id( uint16_t bus, uint16_t device, uint16_t function, uint32_t offset )
+{
+ uint32_t id;
+
+ id = ( 0x01 << 31 )
+ | ( ( bus & 0xFF ) << 16 )
+ | ( ( device & 0x1F ) << 11 )
+ | ( ( function & 0x07 ) << 8 )
+ | ( offset & 0xFC );
+
+ return id;
+}
+
+uint16_t pci_controller_read( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset )
+{
+ uint32_t id = compute_id( bus, device, function, offset );
+
+ port32_write( &controller->command_port, id );
+
+ uint32_t data = port32_read( &controller->data_port );
+
+ // we get 256 byte data blocks aligned to 32-bit addresses
+ // for each offset
+ data = data >> ( ( 8 * ( offset % 4 ) ) & 0xFFFF );
+
+ return data;
+}
+
+void pci_controller_write( pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint32_t offset, uint32_t data )
+{
+ uint32_t id = compute_id( bus, device, function, offset );
+
+ port32_write( &controller->command_port, id );
+ port32_write( &controller->data_port, data );
+}
+