summaryrefslogtreecommitdiff
path: root/src/hardware/pci.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2017-06-10 21:26:24 +0200
committerAndreas Baumann <mail@andreasbaumann.cc>2017-06-10 21:26:24 +0200
commitd6d1bdfefafff50b7b6d15d218c0a188570be541 (patch)
tree15ee8de727d0be5d126efda146b2879de0a72773 /src/hardware/pci.c
parenteea5bf4b859eb56c5772c58ca54937a90a10e7ee (diff)
downloadabaos-d6d1bdfefafff50b7b6d15d218c0a188570be541.tar.gz
abaos-d6d1bdfefafff50b7b6d15d218c0a188570be541.tar.bz2
some big renames into subdirs of aspects
updated README removed size_t in sys/types.h and sys/types.h itself, size_t is in stddef.h
Diffstat (limited to 'src/hardware/pci.c')
-rw-r--r--src/hardware/pci.c187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/hardware/pci.c b/src/hardware/pci.c
new file mode 100644
index 0000000..6b124b2
--- /dev/null
+++ b/src/hardware/pci.c
@@ -0,0 +1,187 @@
+#include "pci.h"
+
+#include "string.h"
+#include "stdio.h"
+
+#define NOF_BUSES 8
+#define NOF_DEVICES_PER_BUS 32
+#define NOF_FUNCTIONS_PER_DEVICE 8
+#define NOF_BARS 6
+
+#define PCI_VENDOR_ID 0x00
+#define PCI_DEVICE_ID 0x02
+#define PCI_REVISION 0x08
+#define PCI_INTERFACE 0x09
+#define PCI_SUBCLASS 0x0A
+#define PCI_CLASS 0x0B
+#define PCI_HEADER_TYPE 0x0E
+#define PCI_BAR_BASE 0x10
+
+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 );
+}
+
+void pci_controller_scan_and_register( pci_controller_t *controller, driver_manager_t *driver_manager, interrupt_t *interrupt )
+{
+ for( int bus = 0; bus < NOF_BUSES; bus++ ) {
+ for( int device = 0; device < NOF_DEVICES_PER_BUS; device++ ) {
+ // TODO: detect single/multi function device from header
+ for( int function = 0; function < NOF_FUNCTIONS_PER_DEVICE; function++ ) {
+ pci_device_descriptor_t device_descriptor;
+ pci_device_descriptor_init( &device_descriptor, controller, bus, device, function );
+
+ // no device
+ if( device_descriptor.device_id == 0x0 ||
+ device_descriptor.device_id == 0xFFFF ) {
+ continue;
+ }
+
+ printf( "%X:%X.%d: %X:%X (interface: %X, class %X:%X, rev: %d)\n",
+ bus, device, function,
+ device_descriptor.vendor_id,
+ device_descriptor.device_id,
+ device_descriptor.interface_id,
+ device_descriptor.class_id,
+ device_descriptor.subclass_id,
+ device_descriptor.revision_id );
+
+ uint8_t header_type = pci_controller_read( controller, bus, device, function, PCI_HEADER_TYPE ) & 0x7F;
+ int max_nof_bars = NOF_BARS;
+ if( header_type & 0x01 ) {
+ max_nof_bars = 2;
+ }
+
+ for( int bar_number = 0; bar_number < max_nof_bars; bar_number++ ) {
+ pci_base_address_register_t bar;
+ pci_base_address_register_init( &bar, controller, bus, device, function, bar_number );
+ if( bar.type == BASE_ADDRESS_REGISTER_TYPE_IO && bar.addr ) {
+ device_descriptor.port_base = (uint32_t)bar.addr;
+ }
+
+ driver_t *driver = pci_device_get_driver( &device_descriptor, interrupt );
+ if( driver ) {
+ driver_manager_add_driver( driver_manager, driver );
+ }
+ }
+ }
+ }
+ }
+}
+
+void pci_device_descriptor_init( pci_device_descriptor_t *descriptor, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function )
+{
+ memset( descriptor, 0, sizeof( pci_device_descriptor_t ) );
+
+ descriptor->vendor_id = pci_controller_read( controller, bus, device, function, PCI_VENDOR_ID );
+ descriptor->device_id = pci_controller_read( controller, bus, device, function, PCI_DEVICE_ID );
+ descriptor->class_id = pci_controller_read( controller, bus, device, function, PCI_CLASS );
+ descriptor->subclass_id = pci_controller_read( controller, bus, device, function, PCI_SUBCLASS );
+ descriptor->interface_id = pci_controller_read( controller, bus, device, function, PCI_INTERFACE );
+ descriptor->revision_id = pci_controller_read( controller, bus, device, function, PCI_REVISION );
+}
+
+void pci_base_address_register_init( pci_base_address_register_t *base_address_register, pci_controller_t *controller, uint16_t bus, uint16_t device, uint16_t function, uint16_t bar )
+{
+ memset( base_address_register, 0, sizeof( pci_base_address_register_t ) );
+
+ uint32_t val = pci_controller_read( controller, bus, device, function, PCI_BAR_BASE + sizeof( uint32_t ) * bar );
+
+ // bit 0 indicates whether we are I/O or memory mapped
+ base_address_register->type = ( val & 0x01 ) ? BASE_ADDRESS_REGISTER_TYPE_IO : BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED;
+
+ switch( base_address_register->type ) {
+ case BASE_ADDRESS_REGISTER_TYPE_IO:
+ base_address_register->addr = (uint8_t *)( val & 0xFFFC );
+ base_address_register->prefetchable = false;
+ break;
+
+ case BASE_ADDRESS_REGISTER_TYPE_MEMORY_MAPPED:
+ switch( val << 1 & 0x03 ) {
+ case 0x00:
+ // 32-bit mode
+ break;
+
+ case 0x01:
+ // 20-bit mode
+ break;
+
+ case 0x02:
+ // 64-bit mode
+ break;
+ }
+ break;
+ }
+}
+
+driver_t *pci_device_get_driver( pci_device_descriptor_t *descriptor, interrupt_t *interrupt )
+{
+ // find a specific device
+ switch( descriptor->vendor_id ) {
+ case 0x10ec: // Realtek Semiconductor
+ switch( descriptor->device_id ) {
+ case 0x8029: // RTL-8029
+ break;
+ }
+ break;
+
+ case 0x8086: // Intel
+ break;
+
+ default:
+ break;
+ }
+
+ // find a generic driver
+ switch( descriptor->class_id ) {
+ case 0x03: // graphics
+ switch( descriptor->subclass_id ) {
+ case 0x00: // VGA
+ break;
+ }
+ break;
+
+ default: // no driver found
+ break;
+ }
+ return NULL;
+}