feat: implemented errno, strtol. Started ustar. Reformatted headers and
code. Added some self-tests. Started prepwork for vfs.
This commit is contained in:
690
kernel/drivers/pci/ide.c
Normal file
690
kernel/drivers/pci/ide.c
Normal file
@@ -0,0 +1,690 @@
|
||||
//
|
||||
// Created by rick on 03-02-21.
|
||||
//
|
||||
// https://wiki.osdev.org/PCI_IDE_Controller
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <myke/drivers/pci/ide.h>
|
||||
#include <myke/debug/debug.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/libk/kprint.h>
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/libk/libk.h>
|
||||
#include <myke/cpu/timer.h>
|
||||
#include <myke/fs/blockdev.h>
|
||||
#include <myke/tasks/locking.h>
|
||||
|
||||
#define ATA_SR_BSY 0x80 // Busy
|
||||
#define ATA_SR_DRDY 0x40 // Drive ready
|
||||
#define ATA_SR_DF 0x20 // Drive write fault
|
||||
#define ATA_SR_DSC 0x10 // Drive seek complete
|
||||
#define ATA_SR_DRQ 0x08 // Data request ready
|
||||
#define ATA_SR_CORR 0x04 // Corrected data
|
||||
#define ATA_SR_IDX 0x02 // Index
|
||||
#define ATA_SR_ERR 0x01 // Error
|
||||
|
||||
#define ATA_ER_BBK 0x80 // Bad block
|
||||
#define ATA_ER_UNC 0x40 // Uncorrectable data
|
||||
#define ATA_ER_MC 0x20 // Media changed
|
||||
#define ATA_ER_IDNF 0x10 // ID mark not found
|
||||
#define ATA_ER_MCR 0x08 // Media change request
|
||||
#define ATA_ER_ABRT 0x04 // Command aborted
|
||||
#define ATA_ER_TK0NF 0x02 // Track 0 not found
|
||||
#define ATA_ER_AMNF 0x01 // No address mark
|
||||
|
||||
#define ATA_CMD_READ_PIO 0x20
|
||||
#define ATA_CMD_READ_PIO_EXT 0x24
|
||||
#define ATA_CMD_READ_DMA 0xC8
|
||||
#define ATA_CMD_READ_DMA_EXT 0x25
|
||||
#define ATA_CMD_WRITE_PIO 0x30
|
||||
#define ATA_CMD_WRITE_PIO_EXT 0x34
|
||||
#define ATA_CMD_WRITE_DMA 0xCA
|
||||
#define ATA_CMD_WRITE_DMA_EXT 0x35
|
||||
#define ATA_CMD_CACHE_FLUSH 0xE7
|
||||
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA
|
||||
#define ATA_CMD_PACKET 0xA0
|
||||
#define ATA_CMD_IDENTIFY_PACKET 0xA1
|
||||
#define ATA_CMD_IDENTIFY 0xEC
|
||||
|
||||
#define ATAPI_CMD_READ 0xA8
|
||||
#define ATAPI_CMD_EJECT 0x1B
|
||||
|
||||
#define ATA_IDENT_DEVICETYPE 0
|
||||
#define ATA_IDENT_CYLINDERS 2
|
||||
#define ATA_IDENT_HEADS 6
|
||||
#define ATA_IDENT_SECTORS 12
|
||||
#define ATA_IDENT_SERIAL 20
|
||||
#define ATA_IDENT_MODEL 54
|
||||
#define ATA_IDENT_CAPABILITIES 98
|
||||
#define ATA_IDENT_FIELDVALID 106
|
||||
#define ATA_IDENT_MAX_LBA 120
|
||||
#define ATA_IDENT_COMMANDSETS 164
|
||||
#define ATA_IDENT_MAX_LBA_EXT 200
|
||||
|
||||
#define ATA_CAP_LBA 0x200
|
||||
|
||||
#define ATA_LBA28_MAX 0x10000000
|
||||
|
||||
#define ATA_HDDDEVSEL_CHS 0b00000000
|
||||
#define ATA_HDDDEVSEL_LBA 0b01000000
|
||||
#define ATA_HDDDEVSEL_DEFAULT 0b10100000
|
||||
|
||||
#define IDE_ATA 0x00
|
||||
#define IDE_ATAPI 0x01
|
||||
|
||||
#define ATA_MASTER 0x00
|
||||
#define ATA_SLAVE 0x01
|
||||
|
||||
// base
|
||||
#define ATA_REG_DATA 0x00
|
||||
#define ATA_REG_ERROR 0x01
|
||||
#define ATA_REG_FEATURES 0x01
|
||||
#define ATA_REG_SECCOUNT0 0x02
|
||||
#define ATA_REG_LBA0 0x03
|
||||
#define ATA_REG_LBA1 0x04
|
||||
#define ATA_REG_LBA2 0x05
|
||||
#define ATA_REG_HDDEVSEL 0x06
|
||||
#define ATA_REG_COMMAND 0x07
|
||||
#define ATA_REG_STATUS 0x07
|
||||
|
||||
// ??
|
||||
#define ATA_REG_SECCOUNT1 0x12
|
||||
#define ATA_REG_LBA3 0x13
|
||||
#define ATA_REG_LBA4 0x14
|
||||
#define ATA_REG_LBA5 0x15
|
||||
|
||||
// ctrl
|
||||
#define ATA_REG_CONTROL 0x22
|
||||
#define ATA_REG_ALTSTATUS 0x22
|
||||
#define ATA_REG_DEVADDRESS 0x23
|
||||
|
||||
// Channels:
|
||||
#define ATA_PRIMARY 0x00
|
||||
#define ATA_SECONDARY 0x01
|
||||
|
||||
// Directions:
|
||||
#define ATA_READ 0x00
|
||||
#define ATA_WRITE 0x01
|
||||
|
||||
struct ide_channel_registers {
|
||||
unsigned short base; // I/O Base.
|
||||
unsigned short ctrl; // Control Base
|
||||
unsigned short bmide; // Bus Master IDE
|
||||
unsigned char nIEN; // nIEN (No Interrupt);
|
||||
} channels[2];
|
||||
|
||||
unsigned char ide_buf[2048] = {0};
|
||||
unsigned static char ide_irq_invoked = 0;
|
||||
unsigned static char atapi_packet[12] = {0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
struct ide_device {
|
||||
unsigned char reserved; // 0 (Empty) or 1 (This Drive really exists).
|
||||
unsigned char channel; // 0 (Primary Channel) or 1 (Secondary Channel).
|
||||
unsigned char drive; // 0 (Master Drive) or 1 (Slave Drive).
|
||||
unsigned short type; // 0: ATA, 1:ATAPI.
|
||||
unsigned short signature; // Drive Signature
|
||||
unsigned short capabilities;// Features.
|
||||
unsigned int commandSets; // Command Sets Supported.
|
||||
unsigned int size; // Size in Sectors.
|
||||
unsigned char model[41]; // Model in string.
|
||||
} ide_devices[4];
|
||||
|
||||
typedef struct {
|
||||
uint8_t device_number: 2;
|
||||
uint8_t print_error: 1;
|
||||
} ide_block_device_info;
|
||||
|
||||
mutex_t *ide_lock = NULL;
|
||||
|
||||
uint8_t ide_read(uint8_t channel, uint8_t reg);
|
||||
|
||||
void ide_write(uint8_t channel, uint8_t reg, uint8_t data);
|
||||
|
||||
uint8_t ide_read(uint8_t channel, uint8_t reg) {
|
||||
uint8_t result;
|
||||
if (reg & 0x10) {
|
||||
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
|
||||
result = port_byte_in(channels[channel].base + (reg & 0xF));
|
||||
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
|
||||
} else if (reg & 0x20) {
|
||||
result = port_byte_in(channels[channel].ctrl + (reg & 0xF));
|
||||
} else {
|
||||
result = port_byte_in(channels[channel].base + reg);
|
||||
}
|
||||
// if (reg < 0x08)
|
||||
// result = port_byte_in(channels[channel].base + reg - 0x00);
|
||||
// else if (reg < 0x0C)
|
||||
// result = port_byte_in(channels[channel].base + reg - 0x06);
|
||||
// else if (reg < 0x0E)
|
||||
// result = port_byte_in(channels[channel].ctrl + reg - 0x0A);
|
||||
// else if (reg < 0x16)
|
||||
// result = port_byte_in(channels[channel].bmide + reg - 0x0E); // todo this case is not handled in new code
|
||||
// if (reg > 0x07 && reg < 0x0C)
|
||||
// ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ide_write(uint8_t channel, uint8_t reg, uint8_t data) {
|
||||
if (reg & 0x10) {
|
||||
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
|
||||
port_byte_out(channels[channel].base + (reg & 0xF), data);
|
||||
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
|
||||
} else if (reg & 0x20) {
|
||||
port_byte_out(channels[channel].ctrl + (reg & 0xF), data);
|
||||
} else {
|
||||
port_byte_out(channels[channel].base + reg, data);
|
||||
}
|
||||
// if (reg > 0x07 && reg < 0x0C)
|
||||
// ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
|
||||
// if (reg < 0x08)
|
||||
// port_byte_out(channels[channel].base + reg - 0x00, data);
|
||||
// else if (reg < 0x0C)
|
||||
// port_byte_out(channels[channel].base + reg - 0x06, data);
|
||||
// else if (reg < 0x0E)
|
||||
// port_byte_out(channels[channel].ctrl + reg - 0x0A, data);
|
||||
// else if (reg < 0x16)
|
||||
// port_byte_out(channels[channel].bmide + reg - 0x0E, data); // todo this case is not handled
|
||||
// if (reg > 0x07 && reg < 0x0C)
|
||||
// ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
|
||||
}
|
||||
|
||||
void ide_read_buffer(unsigned char channel, unsigned char reg, unsigned int *buffer, unsigned int quads) {
|
||||
/* WARNING: This code contains a serious bug. The inline assembly trashes ES and
|
||||
* ESP for all of the code the compiler generates between the inline
|
||||
* assembly blocks.
|
||||
*/
|
||||
if (reg & 0x10) {
|
||||
ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
|
||||
port_double_word_in_repeat(channels[channel].base + (reg & 0xF), buffer, quads);
|
||||
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
|
||||
} else if (reg & 0x20) {
|
||||
port_double_word_in_repeat(channels[channel].base + (reg & 0xF), buffer, quads);
|
||||
} else {
|
||||
port_double_word_in_repeat(channels[channel].base + reg, buffer, quads);
|
||||
}
|
||||
// if (reg > 0x07 && reg < 0x0C) {
|
||||
// ide_write(channel, ATA_REG_CONTROL, 0x80 | channels[channel].nIEN);
|
||||
// }
|
||||
// this assembly is probably necessary when reading paging
|
||||
// asm("pushw %es; movw %ds, %ax; movw %ax, %es" );
|
||||
// if (reg < 0x08) {
|
||||
// port_double_word_in_repeat(channels[channel].base + reg - 0x00, buffer, quads);
|
||||
// } else if (reg < 0x0C) {
|
||||
// port_double_word_in_repeat(channels[channel].base + reg - 0x06, buffer, quads);
|
||||
// } else if (reg < 0x0E) {
|
||||
// port_double_word_in_repeat(channels[channel].ctrl + reg - 0x0A, buffer, quads);
|
||||
// } else if (reg < 0x16) {
|
||||
// port_double_word_in_repeat(channels[channel].bmide + reg - 0x0E, buffer, quads);
|
||||
// }
|
||||
// asm("popw %es;");
|
||||
// if (reg > 0x07 && reg < 0x0C) {
|
||||
// ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN);
|
||||
// }
|
||||
}
|
||||
|
||||
unsigned char ide_polling(unsigned char channel, uint8_t advanced_check) {
|
||||
|
||||
// (I) Delay 400 nanosecond for BSY to be set:
|
||||
// -------------------------------------------------
|
||||
for (int i = 0; i < 4; i++)
|
||||
ide_read(channel, ATA_REG_ALTSTATUS); // Reading the Alternate Status port wastes 100ns; loop four times.
|
||||
|
||||
// (II) Wait for BSY to be cleared:
|
||||
// -------------------------------------------------
|
||||
while (ide_read(channel, ATA_REG_STATUS) & ATA_SR_BSY); // Wait for BSY to be zero.
|
||||
|
||||
if (advanced_check) {
|
||||
unsigned char state = ide_read(channel, ATA_REG_STATUS); // Read Status Register.
|
||||
|
||||
// (III) Check For Errors:
|
||||
// -------------------------------------------------
|
||||
if (state & ATA_SR_ERR)
|
||||
return 2; // Error.
|
||||
|
||||
// (IV) Check If Device fault:
|
||||
// -------------------------------------------------
|
||||
if (state & ATA_SR_DF)
|
||||
return 1; // Device Fault.
|
||||
|
||||
// (V) Check DRQ:
|
||||
// -------------------------------------------------
|
||||
// BSY = 0; DF = 0; ERR = 0 so we should check for DRQ now.
|
||||
if ((state & ATA_SR_DRQ) == 0)
|
||||
return 3; // DRQ should be set
|
||||
|
||||
}
|
||||
|
||||
return 0; // No Error.
|
||||
|
||||
}
|
||||
|
||||
unsigned char ide_print_error(unsigned int drive, unsigned char err) {
|
||||
if (err == 0)
|
||||
return err;
|
||||
|
||||
debug_backtrace(false);
|
||||
|
||||
kprint("IDE:");
|
||||
if (err == 1) {
|
||||
kprint("- Device Fault ");
|
||||
err = 19;
|
||||
} else if (err == 2) {
|
||||
unsigned char st = ide_read(ide_devices[drive].channel, ATA_REG_ERROR);
|
||||
if (st & ATA_ER_AMNF) {
|
||||
kprint("- No Address Mark Found - ");
|
||||
err = 7;
|
||||
}
|
||||
if (st & ATA_ER_TK0NF) {
|
||||
kprint("- No Media or Media Error - ");
|
||||
err = 3;
|
||||
}
|
||||
if (st & ATA_ER_ABRT) {
|
||||
kprint("- Command Aborted - ");
|
||||
err = 20;
|
||||
}
|
||||
if (st & ATA_ER_MCR) {
|
||||
kprint("- No Media or Media Error - ");
|
||||
err = 3;
|
||||
}
|
||||
if (st & ATA_ER_IDNF) {
|
||||
kprint("- ID mark not Found - ");
|
||||
err = 21;
|
||||
}
|
||||
if (st & ATA_ER_MC) {
|
||||
kprint("- No Media or Media Error - ");
|
||||
err = 3;
|
||||
}
|
||||
if (st & ATA_ER_UNC) {
|
||||
kprint("- Uncorrectable Data Error - ");
|
||||
err = 22;
|
||||
}
|
||||
if (st & ATA_ER_BBK) {
|
||||
kprint("- Bad Sectors - ");
|
||||
err = 13;
|
||||
}
|
||||
} else if (err == 3) {
|
||||
kprint("- Reads Nothing - ");
|
||||
err = 23;
|
||||
} else if (err == 4) {
|
||||
kprint("- Write Protected - ");
|
||||
err = 8;
|
||||
} else if (err & 0xF0) {
|
||||
if (err == 0xF1) {
|
||||
kprint("- Unsupported operation by driver - ");
|
||||
} else {
|
||||
kprint(" - Unknown driver error - ");
|
||||
}
|
||||
}
|
||||
printf(" - [%s %s] %s\n",
|
||||
((const char *[]) {"Primary", "Secondary"}[ide_devices[drive].channel]),
|
||||
((const char *[]) {"Master", "Slave"}[ide_devices[drive].drive]),
|
||||
&ide_devices[drive].model);
|
||||
return err;
|
||||
}
|
||||
|
||||
void ide_fix_bar(bar_info *bar, uint32_t default_address, uint32_t size) {
|
||||
if (bar->address == 0x0) {
|
||||
// no need to actually write ti back
|
||||
bar->address = default_address;
|
||||
bar->prefetchable = 0;
|
||||
bar->type = 0;
|
||||
bar->is_io_space = 1;
|
||||
bar->size = size;
|
||||
}
|
||||
}
|
||||
|
||||
bool ide_pci_init_channels(pci_device *device) {
|
||||
pci_config_write_byte(device->bus, device->slot, device->func, PCI_CONFIG_INTERRUPT_LINE, 0xFE);
|
||||
if (pci_config_read_byte(device->bus, device->slot, device->func, PCI_CONFIG_INTERRUPT_LINE) == 0xFE) {
|
||||
#ifdef IDE_ENABLE_INTERRUPT
|
||||
#error "Interrupt not supported"
|
||||
k_panics("NOT SUPPORTED");
|
||||
#else
|
||||
pci_config_write_byte(device->bus, device->slot, device->func, PCI_CONFIG_INTERRUPT_LINE,
|
||||
PCI_INTERRUPT_LINE_DISABLED);
|
||||
#endif
|
||||
}
|
||||
pci_init_bar(device, 0);
|
||||
pci_init_bar(device, 1);
|
||||
pci_init_bar(device, 2);
|
||||
pci_init_bar(device, 3);
|
||||
pci_init_bar(device, 4);
|
||||
|
||||
if (!device->bar0.present
|
||||
|| !device->bar1.present
|
||||
|| !device->bar2.present
|
||||
|| !device->bar3.present
|
||||
|| !device->bar4.present) {
|
||||
k_panics("IDE Missing bars");
|
||||
return false;
|
||||
}
|
||||
ide_fix_bar(&device->bar0, 0x1F0, 8);
|
||||
ide_fix_bar(&device->bar1, 0x3F6, 4);
|
||||
ide_fix_bar(&device->bar2, 0x170, 8);
|
||||
ide_fix_bar(&device->bar3, 0x376, 4);
|
||||
|
||||
channels[ATA_PRIMARY].base = device->bar0.address;
|
||||
channels[ATA_PRIMARY].ctrl = device->bar1.address;
|
||||
channels[ATA_SECONDARY].base = device->bar2.address;
|
||||
channels[ATA_SECONDARY].ctrl = device->bar3.address;
|
||||
channels[ATA_PRIMARY].bmide = device->bar4.address + 0; // Bus Master IDE
|
||||
channels[ATA_SECONDARY].bmide = device->bar4.address + 8; // Bus Master IDE
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
ide_block_dev_access(const block_device_t *device, uint8_t direction, uint32_t lba, uint8_t sectors, void *target) {
|
||||
ide_block_device_info *info = device->device_info;
|
||||
uint8_t result = ide_access(direction, info->device_number, lba, sectors, target);
|
||||
if (result != 0) {
|
||||
if (info->print_error) {
|
||||
ide_print_error(info->device_number, result);
|
||||
}
|
||||
return BLOCK_DEV_ACCESS_ERR;
|
||||
}
|
||||
return BLOCK_DEV_ACCESS_OK;
|
||||
}
|
||||
|
||||
void ide_register_block_devices() {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
if (!ide_devices[i].reserved) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ide_block_device_info *info = malloc(sizeof(ide_block_device_info)); // todo free for this one
|
||||
info->device_number = i;
|
||||
info->print_error = 1;
|
||||
|
||||
block_device_t device = {
|
||||
.flags.present = 1,
|
||||
.flags.root_device = 1,
|
||||
.device_info = info,
|
||||
.num_lba = ide_devices[i].size,
|
||||
.block_size = 0x200,
|
||||
.access = ide_block_dev_access,
|
||||
};
|
||||
sprintf(device.identifier, "ide%d", i);
|
||||
|
||||
block_dev_register(&device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t used ide_pci_validate(const pci_device *device) {
|
||||
if (device->class != PCI_CLASS_MASS_STORAGE
|
||||
|| device->subclass != PCI_SUB_CLASS_IDE
|
||||
|| (device->programInterface != 0x8A && device->programInterface != 0x80)) {
|
||||
return PCI_VALIDATE_FAIL;
|
||||
}
|
||||
// todo other validations
|
||||
return PCI_VALIDATE_OK;
|
||||
}
|
||||
|
||||
uint8_t used ide_pci_initialize(pci_device *device) {
|
||||
|
||||
if (!ide_pci_init_channels(device)) {
|
||||
return PCI_INIT_FAIL;
|
||||
}
|
||||
|
||||
if (ide_lock != NULL) {
|
||||
k_panics("IDE already initialized\n");
|
||||
}
|
||||
ide_lock = mutex_create();
|
||||
mutex_acquire(ide_lock);
|
||||
|
||||
// disable IRQ
|
||||
ide_write(ATA_PRIMARY, ATA_REG_CONTROL, 2);
|
||||
ide_write(ATA_SECONDARY, ATA_REG_CONTROL, 2);
|
||||
|
||||
int count = 0;
|
||||
// 3- Detect ATA-ATAPI Devices:
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
|
||||
unsigned char err = 0, type = IDE_ATA, status;
|
||||
ide_devices[count].reserved = 0; // Assuming that no drive here.
|
||||
|
||||
// (I) Select Drive:
|
||||
ide_write(i, ATA_REG_HDDEVSEL, 0xA0 | (j << 4)); // Select Drive.
|
||||
sleep(1); // Wait 1ms for drive select to work.
|
||||
|
||||
// (II) Send ATA Identify Command:
|
||||
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
||||
sleep(1); // This function should be implemented in your OS. which waits for 1 ms.
|
||||
// it is based on System Timer Device Driver.
|
||||
|
||||
// (III) Polling:
|
||||
if (ide_read(i, ATA_REG_STATUS) == 0) continue; // If Status = 0, No Device.
|
||||
|
||||
while (1) {
|
||||
status = ide_read(i, ATA_REG_STATUS);
|
||||
if ((status & ATA_SR_ERR)) {
|
||||
err = 1;
|
||||
break;
|
||||
} // If Err, Device is not ATA.
|
||||
if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRQ)) break; // Everything is right.
|
||||
}
|
||||
|
||||
// (IV) Probe for ATAPI Devices:
|
||||
|
||||
if (err != 0) {
|
||||
unsigned char cl = ide_read(i, ATA_REG_LBA1);
|
||||
unsigned char ch = ide_read(i, ATA_REG_LBA2);
|
||||
|
||||
if (cl == 0x14 && ch == 0xEB) {
|
||||
type = IDE_ATAPI;
|
||||
} else if (cl == 0x69 && ch == 0x96) {
|
||||
type = IDE_ATAPI;
|
||||
} else {
|
||||
continue; // Unknown Type (may not be a device).
|
||||
}
|
||||
|
||||
ide_write(i, ATA_REG_COMMAND, ATA_CMD_IDENTIFY_PACKET);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// (V) Read Identification Space of the Device:
|
||||
ide_read_buffer(i, ATA_REG_DATA, (unsigned int *) ide_buf, 128);
|
||||
|
||||
// (VI) Read Device Parameters:
|
||||
ide_devices[count].reserved = 1;
|
||||
ide_devices[count].type = type;
|
||||
ide_devices[count].channel = i;
|
||||
ide_devices[count].drive = j;
|
||||
ide_devices[count].signature = *((unsigned short *) (ide_buf + ATA_IDENT_DEVICETYPE));
|
||||
ide_devices[count].capabilities = *((unsigned short *) (ide_buf + ATA_IDENT_CAPABILITIES));
|
||||
ide_devices[count].commandSets = *((unsigned int *) (ide_buf + ATA_IDENT_COMMANDSETS));
|
||||
|
||||
// (VII) Get Size:
|
||||
if (ide_devices[count].commandSets & (1 << 26))
|
||||
// Device uses 48-Bit Addressing:
|
||||
ide_devices[count].size = *((unsigned int *) (ide_buf + ATA_IDENT_MAX_LBA_EXT));
|
||||
else
|
||||
// Device uses CHS or 28-bit Addressing:
|
||||
ide_devices[count].size = *((unsigned int *) (ide_buf + ATA_IDENT_MAX_LBA));
|
||||
|
||||
// (VIII) String indicates model of device (like Western Digital HDD and SONY DVD-RW...):
|
||||
for (int k = 0; k < 40; k += 2) {
|
||||
ide_devices[count].model[k] = ide_buf[ATA_IDENT_MODEL + k + 1];
|
||||
ide_devices[count].model[k + 1] = ide_buf[ATA_IDENT_MODEL + k];
|
||||
}
|
||||
ide_devices[count].model[40] = 0; // Terminate String.
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
mutex_release(ide_lock);
|
||||
ide_register_block_devices();
|
||||
|
||||
return PCI_INIT_OK;
|
||||
}
|
||||
|
||||
void ide_print_devices() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (ide_devices[i].reserved == 1) {
|
||||
printf("Drive %d: %s Drive %dMB - %s\n",
|
||||
i,
|
||||
((const char *[]) {"ATA", "ATAPI"}[ide_devices[i].type]),
|
||||
ide_devices[i].size / 1024 / 2,
|
||||
ide_devices[i].model);
|
||||
} else {
|
||||
printf("Drive %d disconnected\n", i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ide_read_ata_access(uint8_t direction, uint8_t drive, uint32_t lba, uint8_t numsects, void *target) {
|
||||
uint8_t lba_mode /* 0: CHS, 1:LBA28, 2: LBA48 */, dma /* 0: No DMA, 1: DMA */, cmd;
|
||||
uint8_t lba_io[6];
|
||||
uint8_t channel = ide_devices[drive].channel;
|
||||
uint8_t slavebit = ide_devices[drive].drive;
|
||||
uint32_t bus = channels[channel].base;
|
||||
uint32_t words = 256;
|
||||
uint16_t cyl, i;
|
||||
uint8_t head, sect, err;
|
||||
|
||||
ide_write(channel, ATA_REG_CONTROL, channels[channel].nIEN = (ide_irq_invoked = 0x0) + 0x02);
|
||||
|
||||
// setup LBA data
|
||||
if (lba >= ATA_LBA28_MAX) { // Sure Drive should support LBA in this case, or you are
|
||||
// giving a wrong LBA.
|
||||
// LBA48:
|
||||
lba_mode = 2;
|
||||
lba_io[0] = (lba & 0x000000FF) >> 0;
|
||||
lba_io[1] = (lba & 0x0000FF00) >> 8;
|
||||
lba_io[2] = (lba & 0x00FF0000) >> 16;
|
||||
lba_io[3] = (lba & 0xFF000000) >> 24;
|
||||
lba_io[4] = 0; // LBA28 is integer, so 32-bits are enough to access 2TB.
|
||||
lba_io[5] = 0; // LBA28 is integer, so 32-bits are enough to access 2TB.
|
||||
head = 0; // Lower 4-bits of HDDEVSEL are not used here.
|
||||
} else if (ide_devices[drive].capabilities & ATA_CAP_LBA) { // Drive supports LBA?
|
||||
// LBA28:
|
||||
lba_mode = 1;
|
||||
lba_io[0] = (lba & 0x00000FF) >> 0;
|
||||
lba_io[1] = (lba & 0x000FF00) >> 8;
|
||||
lba_io[2] = (lba & 0x0FF0000) >> 16;
|
||||
lba_io[3] = 0; // These Registers are not used here.
|
||||
lba_io[4] = 0; // These Registers are not used here.
|
||||
lba_io[5] = 0; // These Registers are not used here.
|
||||
head = (lba & 0xF000000) >> 24;
|
||||
} else {
|
||||
// CHS:
|
||||
lba_mode = 0;
|
||||
sect = (lba % 63) + 1;
|
||||
cyl = (lba + 1 - sect) / (16 * 63);
|
||||
lba_io[0] = sect;
|
||||
lba_io[1] = (cyl >> 0) & 0xFF;
|
||||
lba_io[2] = (cyl >> 8) & 0xFF;
|
||||
lba_io[3] = 0;
|
||||
lba_io[4] = 0;
|
||||
lba_io[5] = 0;
|
||||
head = (lba + 1 - sect) % (16 * 63) / (63); // Head number is written to HDDEVSEL lower 4-bits.
|
||||
}
|
||||
|
||||
// check if DMA is available
|
||||
dma = 0; // maybe later
|
||||
|
||||
// wait for the drive to have time for us
|
||||
while (ide_read(channel, ATA_REG_STATUS) & ATA_SR_BSY) {}
|
||||
|
||||
if (lba_mode == 0) {
|
||||
ide_write(channel,
|
||||
ATA_REG_HDDEVSEL,
|
||||
ATA_HDDDEVSEL_DEFAULT | ATA_HDDDEVSEL_CHS | (slavebit << 4) | head); // Drive & CHS.
|
||||
} else {
|
||||
ide_write(channel,
|
||||
ATA_REG_HDDEVSEL,
|
||||
ATA_HDDDEVSEL_DEFAULT | ATA_HDDDEVSEL_LBA | (slavebit << 4) | head); // Drive & LBA
|
||||
}
|
||||
|
||||
// store data
|
||||
if (lba_mode == 2) {
|
||||
ide_write(channel, ATA_REG_SECCOUNT1, 0);
|
||||
ide_write(channel, ATA_REG_LBA3, lba_io[3]);
|
||||
ide_write(channel, ATA_REG_LBA4, lba_io[4]);
|
||||
ide_write(channel, ATA_REG_LBA5, lba_io[5]);
|
||||
}
|
||||
ide_write(channel, ATA_REG_SECCOUNT0, numsects);
|
||||
ide_write(channel, ATA_REG_LBA0, lba_io[0]);
|
||||
ide_write(channel, ATA_REG_LBA1, lba_io[1]);
|
||||
ide_write(channel, ATA_REG_LBA2, lba_io[2]);
|
||||
|
||||
// pick correct ccommand
|
||||
if (lba_mode == 0 && dma == 0 && direction == 0) cmd = ATA_CMD_READ_PIO;
|
||||
if (lba_mode == 1 && dma == 0 && direction == 0) cmd = ATA_CMD_READ_PIO;
|
||||
if (lba_mode == 2 && dma == 0 && direction == 0) cmd = ATA_CMD_READ_PIO_EXT;
|
||||
// if (lba_mode == 0 && dma == 1 && direction == 0) cmd = ATA_CMD_READ_DMA;
|
||||
// if (lba_mode == 1 && dma == 1 && direction == 0) cmd = ATA_CMD_READ_DMA;
|
||||
// if (lba_mode == 2 && dma == 1 && direction == 0) cmd = ATA_CMD_READ_DMA_EXT;
|
||||
if (lba_mode == 0 && dma == 0 && direction == 1) cmd = ATA_CMD_WRITE_PIO;
|
||||
if (lba_mode == 1 && dma == 0 && direction == 1) cmd = ATA_CMD_WRITE_PIO;
|
||||
if (lba_mode == 2 && dma == 0 && direction == 1) cmd = ATA_CMD_WRITE_PIO_EXT;
|
||||
// if (lba_mode == 0 && dma == 1 && direction == 1) cmd = ATA_CMD_WRITE_DMA;
|
||||
// if (lba_mode == 1 && dma == 1 && direction == 1) cmd = ATA_CMD_WRITE_DMA;
|
||||
// if (lba_mode == 2 && dma == 1 && direction == 1) cmd = ATA_CMD_WRITE_DMA_EXT;
|
||||
ide_write(channel, ATA_REG_COMMAND, cmd); // Send the Command.
|
||||
|
||||
void *cur_addr = target;
|
||||
// read response
|
||||
if (dma) {
|
||||
if (direction == 0);
|
||||
// DMA Read.
|
||||
else;
|
||||
// DMA Write.
|
||||
} else {
|
||||
if (direction == 0) {
|
||||
// PIO Read.
|
||||
for (i = 0; i < numsects; i++) {
|
||||
if ((err = ide_polling(channel, 1))) {
|
||||
ide_print_error(drive, err);
|
||||
return err; // Polling, set error and exit if there is.
|
||||
}
|
||||
port_word_in_repeat(bus, cur_addr, words);
|
||||
cur_addr += (words * 2);
|
||||
}
|
||||
} else {
|
||||
// PIO Write.
|
||||
for (i = 0; i < numsects; i++) {
|
||||
ide_polling(channel, 0); // Polling.
|
||||
port_word_out_repeat(bus, cur_addr, words);
|
||||
cur_addr += (words * 2);
|
||||
}
|
||||
ide_write(channel, ATA_REG_COMMAND, (char[]) {ATA_CMD_CACHE_FLUSH,
|
||||
ATA_CMD_CACHE_FLUSH,
|
||||
ATA_CMD_CACHE_FLUSH_EXT}[lba_mode]);
|
||||
ide_polling(channel, 0); // Polling.
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t ide_access(uint8_t direction, uint8_t drive, uint32_t lba, uint8_t numsects, void *target) {
|
||||
if (drive > 3
|
||||
|| ide_devices[drive].reserved == 0
|
||||
|| ide_devices[drive].type == IDE_ATAPI) {
|
||||
return 0xF1;
|
||||
}
|
||||
mutex_acquire(ide_lock);
|
||||
uint8_t result = ide_read_ata_access(direction, drive, lba, numsects, target);
|
||||
mutex_release(ide_lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
PCI_DRIVER(900) = {
|
||||
.name = "pci-ide",
|
||||
.description = "Default PCI IDE Driver",
|
||||
.validatable = true,
|
||||
.initialisable = true,
|
||||
.match.class = PCI_CLASS_MASS_STORAGE,
|
||||
.match.subclass = PCI_SUB_CLASS_IDE,
|
||||
.mask.class = true,
|
||||
.mask.subclass = true,
|
||||
.validate = ide_pci_validate,
|
||||
.initialize = ide_pci_initialize,
|
||||
};
|
||||
|
||||
383
kernel/drivers/pci/pci.c
Normal file
383
kernel/drivers/pci/pci.c
Normal file
@@ -0,0 +1,383 @@
|
||||
//
|
||||
// Created by rick on 02-02-21.
|
||||
//
|
||||
// https://wiki.osdev.org/PCI
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <myke/drivers/pci/pci.h>
|
||||
#include <myke/drivers/ports.h>
|
||||
#include <myke/libk/libk.h>
|
||||
|
||||
#ifdef ENABLE_PCIPP
|
||||
|
||||
#include <myke/drivers/pci/pci_devices.h>
|
||||
|
||||
#endif
|
||||
|
||||
#define PCI_CONFIG_ENABLE (1 << 31)
|
||||
|
||||
#define PCI_CONFIG_SHIFT_BUS_NUMBER 16
|
||||
#define PCI_CONFIG_SHIFT_DEV_NUMBER 11
|
||||
#define PCI_CONFIG_SHIFT_FUNC_NUMBER 8
|
||||
|
||||
#define PCI_CONFIG_LINE_0 0x00
|
||||
#define PCI_CONFIG_LINE_1 0x01
|
||||
#define PCI_CONFIG_LINE_2 0x08
|
||||
#define PCI_CONFIG_LINE_3 0x0C
|
||||
|
||||
|
||||
#define MAX_PCI_DRIVERS 64
|
||||
#define MAX_PCI_DEVICES 64
|
||||
|
||||
#define MASK_BAR_IOSPACE 0xFFFFFFFC
|
||||
#define MASK_BAR_MEMSPACE 0xFFFFFFF0
|
||||
|
||||
//const pci_driver *pci_drivers[MAX_PCI_DRIVERS];
|
||||
extern struct pci_driver __start_pci_driver[];
|
||||
extern struct pci_driver __stop_pci_driver[];
|
||||
#define NUM_DRIVERS ((size_t)(__stop_pci_driver - __start_pci_driver))
|
||||
#define DRIVER(i) ((__start_pci_driver) + (i))
|
||||
int last_pci_device_index = 0;
|
||||
pci_device pci_devices[MAX_PCI_DEVICES];
|
||||
|
||||
void pci_check_bus(uint8_t bus);
|
||||
|
||||
uint8_t used pci_secondary_bus_use(const pci_device *device) {
|
||||
uint8_t secondary_bus = pci_config_read_byte(device->bus, device->slot, device->func,
|
||||
PCI_CONFIG_SECONDARY_BUS_NUMBER);
|
||||
pci_check_bus(secondary_bus);
|
||||
return PCI_USE_OK;
|
||||
}
|
||||
|
||||
uint32_t pci_config_address(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
return PCI_CONFIG_ENABLE
|
||||
| ((uint32_t) bus << PCI_CONFIG_SHIFT_BUS_NUMBER)
|
||||
| ((uint32_t) slot << PCI_CONFIG_SHIFT_DEV_NUMBER)
|
||||
| ((uint32_t) func << PCI_CONFIG_SHIFT_FUNC_NUMBER)
|
||||
| (offset & 0xFC);
|
||||
}
|
||||
|
||||
uint32_t pci_config_read_double_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t address = pci_config_address(bus, slot, func, offset);
|
||||
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
return port_double_word_in(PORT_PCI_CONFIG_DATA);
|
||||
}
|
||||
|
||||
uint16_t pci_config_read_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t address = pci_config_address(bus, slot, func, offset);
|
||||
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
return port_double_word_in(PORT_PCI_CONFIG_DATA) >> ((offset & 2) * 8) & 0xFFFF;
|
||||
}
|
||||
|
||||
uint8_t pci_config_read_byte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) {
|
||||
uint32_t address = pci_config_address(bus, slot, func, offset);
|
||||
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
return port_double_word_in(PORT_PCI_CONFIG_DATA) >> ((offset & 0b11) * 8) & 0xFF;
|
||||
}
|
||||
|
||||
void pci_config_write_double_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint32_t value) {
|
||||
uint32_t address = pci_config_address(bus, slot, func, offset);
|
||||
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
port_double_word_out(PORT_PCI_CONFIG_DATA, value);
|
||||
}
|
||||
|
||||
void pci_config_write_word(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint16_t value) {
|
||||
uint32_t address = pci_config_address(bus, slot, func, offset);
|
||||
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
port_word_out(PORT_PCI_CONFIG_DATA, value);
|
||||
}
|
||||
|
||||
void pci_config_write_byte(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, uint8_t value) {
|
||||
uint32_t address = pci_config_address(bus, slot, func, offset);
|
||||
port_double_word_out(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
port_byte_out(PORT_PCI_CONFIG_DATA, value);
|
||||
}
|
||||
|
||||
pci_command_register_t pci_get_config(pci_device *device) {
|
||||
pci_command_register_t status;
|
||||
status.value = pci_config_read_word(device->bus, device->slot, device->func, PCI_CONFIG_COMMAND);
|
||||
return status;
|
||||
}
|
||||
|
||||
void pci_set_status(pci_device *device, pci_status_register_t status) {
|
||||
pci_config_write_word(device->bus, device->slot, device->func, PCI_CONFIG_STATUS, status.value);
|
||||
}
|
||||
|
||||
pci_status_register_t pci_get_status(pci_device *device) {
|
||||
pci_status_register_t status;
|
||||
status.value = pci_config_read_word(device->bus, device->slot, device->func, PCI_CONFIG_STATUS);
|
||||
return status;
|
||||
}
|
||||
|
||||
uint16_t pci_get_vendor_id(uint8_t bus, uint8_t slot, uint8_t func) {
|
||||
return pci_config_read_word(bus, slot, func, PCI_CONFIG_VENDOR_ID);
|
||||
}
|
||||
|
||||
uint8_t pci_get_header_type(uint8_t bus, uint8_t slot, uint8_t func) {
|
||||
return pci_config_read_byte(bus, slot, func, PCI_CONFIG_HEADER_TYPE);
|
||||
}
|
||||
|
||||
void pci_pick_driver(pci_device *device) {
|
||||
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
|
||||
struct pci_driver *driver = DRIVER(i);
|
||||
if (driver == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (driver->mask.class && driver->match.class != device->class) {
|
||||
continue;
|
||||
}
|
||||
if (driver->mask.subclass && driver->match.subclass != device->subclass) {
|
||||
continue;
|
||||
}
|
||||
if (driver->mask.interface && driver->match.interface != device->programInterface) {
|
||||
continue;
|
||||
}
|
||||
if (driver->mask.vendor && driver->match.vendor != device->vendorId) {
|
||||
continue;
|
||||
}
|
||||
if (driver->mask.device && driver->match.device != device->deviceId) {
|
||||
continue;
|
||||
}
|
||||
if (driver->direct_use) {
|
||||
if (driver->use(device) != PCI_USE_OK) {
|
||||
continue;
|
||||
}
|
||||
} else if (driver->validatable) {
|
||||
if (driver->validate(device) != PCI_VALIDATE_OK) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
device->pci_driver = DRIVER(i);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_check_function(uint8_t bus, uint8_t slot, uint8_t func) {
|
||||
pci_devices[last_pci_device_index].bus = bus;
|
||||
pci_devices[last_pci_device_index].slot = slot;
|
||||
pci_devices[last_pci_device_index].func = func;
|
||||
pci_devices[last_pci_device_index].config_line_0 = pci_config_read_double_word(bus, slot, func, PCI_CONFIG_LINE_0);
|
||||
pci_devices[last_pci_device_index].config_line_2 = pci_config_read_double_word(bus, slot, func, PCI_CONFIG_LINE_2);
|
||||
pci_devices[last_pci_device_index].config_line_3 = pci_config_read_double_word(bus, slot, func, PCI_CONFIG_LINE_3);
|
||||
pci_devices[last_pci_device_index].device_state.present = 1;
|
||||
last_pci_device_index++;
|
||||
|
||||
pci_pick_driver(&pci_devices[last_pci_device_index - 1]);
|
||||
|
||||
// todo do something with the function
|
||||
}
|
||||
|
||||
void pci_check_device(uint8_t bus, uint8_t device) {
|
||||
uint8_t function = 0;
|
||||
uint16_t vendor_id = pci_get_vendor_id(bus, device, function);
|
||||
if (vendor_id == 0xFFFF) return;
|
||||
pci_check_function(bus, device, function);
|
||||
uint8_t header_type = pci_get_header_type(bus, device, function);
|
||||
if (header_type & PCI_HEADER_TYPE_MULTI_FUNC) {
|
||||
for (function = 1; function < 8; ++function) {
|
||||
if (pci_get_vendor_id(bus, device, function) != 0xFFFF) {
|
||||
pci_check_function(bus, device, function);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pci_check_bus(uint8_t bus) {
|
||||
for (int device = 0; device < 32; ++device) {
|
||||
pci_check_device(bus, device);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_scan() {
|
||||
if (last_pci_device_index != 0) {
|
||||
k_panics("Can only scan once!");
|
||||
}
|
||||
uint8_t header_type = pci_get_header_type(0, 0, 0);
|
||||
if (header_type & PCI_HEADER_TYPE_MULTI_FUNC) {
|
||||
// multiple pci host controllers
|
||||
for (int function = 0; function < 8; ++function) {
|
||||
pci_check_bus(function);
|
||||
}
|
||||
} else {
|
||||
pci_check_bus(0);
|
||||
}
|
||||
}
|
||||
|
||||
void pci_init_drivers() {
|
||||
for (int device_index = 0; device_index < MAX_PCI_DEVICES; ++device_index) {
|
||||
if (!pci_devices[device_index].device_state.present) {
|
||||
continue;
|
||||
}
|
||||
if (pci_devices[device_index].driver_state.initialized) {
|
||||
continue; // already done
|
||||
}
|
||||
if (pci_devices[device_index].pci_driver == NULL) {
|
||||
continue; // no driver found
|
||||
}
|
||||
if (pci_devices[device_index].pci_driver->initialisable) {
|
||||
pci_devices[device_index].pci_driver->initialize(&pci_devices[device_index]);
|
||||
}
|
||||
pci_devices[device_index].driver_state.initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void pci_print_info() {
|
||||
for (int i = 0; i < last_pci_device_index; ++i) {
|
||||
printf("PCI BSF: %2x/%2x/%2x, CSI: %2x/%2x/%2x, V/D: %4x/%4x, driver: %s\n",
|
||||
pci_devices[i].bus, pci_devices[i].slot, pci_devices[i].func,
|
||||
pci_devices[i].class, pci_devices[i].subclass, pci_devices[i].programInterface,
|
||||
pci_devices[i].vendorId, pci_devices[i].deviceId,
|
||||
(pci_devices[i].pci_driver == NULL ? "none" : pci_devices[i].pci_driver->name));
|
||||
}
|
||||
}
|
||||
|
||||
void pci_dump_caps_internal(pci_device *device) {
|
||||
if (pci_devices->headerType >= 0x02) {
|
||||
printf("\tNot supported for PCI-to-CardBus bridge\n");
|
||||
return;
|
||||
}
|
||||
if (!pci_get_status(device).status.capabilities_list) {
|
||||
printf("\tNo caps\n");
|
||||
return;
|
||||
}
|
||||
uint8_t cap_ptr = pci_config_read_byte(device->bus, device->slot, device->func, PCI_CONFIG_CAP_POINTER);
|
||||
printf("\t%x\n", cap_ptr);
|
||||
// todo traverse
|
||||
}
|
||||
|
||||
void pci_dump_caps() {
|
||||
for (int i = 0; i < last_pci_device_index; ++i) {
|
||||
printf("PCI BSF: %2x/%2x/%2x, CSI: %2x/%2x/%2x, V/D: %4x/%4x, driver: %s\n",
|
||||
pci_devices[i].bus, pci_devices[i].slot, pci_devices[i].func,
|
||||
pci_devices[i].class, pci_devices[i].subclass, pci_devices[i].programInterface,
|
||||
pci_devices[i].vendorId, pci_devices[i].deviceId,
|
||||
(pci_devices[i].pci_driver == NULL ? "none" : pci_devices[i].pci_driver->name));
|
||||
pci_dump_caps_internal(&pci_devices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_PCIPP
|
||||
|
||||
void pci_pretty_print() {
|
||||
for (int i = 0; i < last_pci_device_index; ++i) {
|
||||
char *class = NULL;
|
||||
char *subclass = NULL;
|
||||
char *function = NULL;
|
||||
pci_device_info *class_info = NULL;
|
||||
pci_device_info *subclass_info = NULL;
|
||||
pci_device_info *function_info = NULL;
|
||||
pci_device_info *current = pci_root_info;
|
||||
while (current->name != NULL) {
|
||||
if (current->code == pci_devices[i].class) {
|
||||
class = current->name;
|
||||
class_info = current;
|
||||
break;
|
||||
}
|
||||
current = current + 1;
|
||||
}
|
||||
if (class_info != NULL && class_info->sub != NULL) {
|
||||
current = class_info->sub;
|
||||
while (current->name != NULL) {
|
||||
if (current->code == pci_devices[i].subclass) {
|
||||
subclass = current->name;
|
||||
subclass_info = current;
|
||||
break;
|
||||
}
|
||||
current = current + 1;
|
||||
}
|
||||
}
|
||||
if (subclass_info != NULL && subclass_info->sub != NULL) {
|
||||
current = subclass_info->sub;
|
||||
while (current->name != NULL) {
|
||||
if (current->code == pci_devices[i].programInterface) {
|
||||
function = current->name;
|
||||
function_info = current;
|
||||
break;
|
||||
}
|
||||
current = current + 1;
|
||||
}
|
||||
}
|
||||
printf("PCI BSF: %2x/%2x/%2x %s %s %s\n",
|
||||
pci_devices[i].bus, pci_devices[i].slot, pci_devices[i].func,
|
||||
class, subclass, function);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void pci_init_bar(pci_device *device, uint8_t bar_index) {
|
||||
if (device->headerType != 0x00) {
|
||||
k_panics("Only header 0x00 supported for now");
|
||||
return;
|
||||
}
|
||||
uint8_t offset = 0;
|
||||
bar_info *bar;
|
||||
switch (bar_index) {
|
||||
case 0:
|
||||
offset = PCI_CONFIG_BAR0;
|
||||
bar = &device->bar0;
|
||||
break;
|
||||
case 1:
|
||||
offset = PCI_CONFIG_BAR1;
|
||||
bar = &device->bar1;
|
||||
break;
|
||||
case 2:
|
||||
offset = PCI_CONFIG_BAR2;
|
||||
bar = &device->bar2;
|
||||
break;
|
||||
case 3:
|
||||
offset = PCI_CONFIG_BAR3;
|
||||
bar = &device->bar3;
|
||||
break;
|
||||
case 4:
|
||||
offset = PCI_CONFIG_BAR4;
|
||||
bar = &device->bar4;
|
||||
break;
|
||||
case 5:
|
||||
offset = PCI_CONFIG_BAR5;
|
||||
bar = &device->bar5;
|
||||
break;
|
||||
default:
|
||||
k_panics("Bar index too high");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint32_t original_address = pci_config_read_double_word(device->bus, device->slot, device->func, offset);
|
||||
pci_config_write_double_word(device->bus, device->slot, device->func, offset, 0xFFFFFFFF);
|
||||
uint32_t masked_size = pci_config_read_double_word(device->bus, device->slot, device->func, offset);
|
||||
|
||||
if (original_address & 0x1) {
|
||||
// IO Space
|
||||
bar->size = ~(masked_size & MASK_BAR_IOSPACE) + 1;
|
||||
bar->address = original_address & MASK_BAR_IOSPACE;
|
||||
bar->is_io_space = 1;
|
||||
} else {
|
||||
// Memory space
|
||||
bar->size = ~(masked_size & MASK_BAR_MEMSPACE) + 1;
|
||||
bar->address = original_address & 0xFFFFFFF0;
|
||||
bar->is_io_space = 0;
|
||||
bar->type = (original_address & 0b110) >> 1;
|
||||
bar->prefetchable = (original_address & 0b1000) >> 3;
|
||||
}
|
||||
// todo identify conflicts, move to different address
|
||||
pci_config_write_double_word(device->bus, device->slot, device->func, offset, original_address);
|
||||
bar->present = 1;
|
||||
}
|
||||
|
||||
// internal drivers
|
||||
PCI_DRIVER(0) = {
|
||||
.name = "pci-secondary-bus",
|
||||
.description = "A PCI bus connected to the primary bus",
|
||||
.match.class = PCI_CLASS_BRIDGE,
|
||||
.match.subclass = PCI_SUB_CLASS_PCI_PCI_BRIDGE_4,
|
||||
.mask.class = true,
|
||||
.mask.subclass = true,
|
||||
.direct_use = true,
|
||||
.use = pci_secondary_bus_use,
|
||||
};
|
||||
|
||||
// todo https://wiki.osdev.org/Universal_Serial_Bus if i dare
|
||||
Reference in New Issue
Block a user