/* Copyright 1999, Brian J. Swetland. All rights reserved. ** Distributed under the terms of the OpenBLT License */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <kernel/driver.h> #include "pci.h" typedef struct confadd { byte reg:8; byte func:3; byte dev:5; byte bus:8; byte rsvd:7; byte enable:1; } confadd; dword pci_read(int bus, int dev, int func, int reg, int bytes) { word base; union { confadd c; dword n; } u; u.c.enable = 1; u.c.rsvd = 0; u.c.bus = bus; u.c.dev = dev; u.c.func = func; u.c.reg = reg & 0xFC; out32(0xCF8, u.n); base = 0xCFC + (reg & 0x03); switch(bytes){ case 1: return in(base); case 2: return in16(base); case 4: return in32(base); default: return 0; } } void pci_write(int bus, int dev, int func, int reg, dword v, int bytes) { word base; union { confadd c; dword n; } u; u.c.enable = 1; u.c.rsvd = 0; u.c.bus = bus; u.c.dev = dev; u.c.func = func; u.c.reg = reg & 0xFC; base = 0xCFC + (reg & 0x03); out32(0xCF8, u.n); switch(bytes){ case 1: out(base, (byte) v); break; case 2: out16(base, (word) v); break; case 4: out32(base, v); break; } } int pci_probe(int bus, int dev, int func, pci_cfg_t *cfg) { dword *word = (dword *) cfg; dword v; int i; for(i=0;i<4;i++){ word[i] = pci_read(bus,dev,func,4*i,4); } if(cfg->vendor_id == 0xffff) return 1; cfg->bus = bus; cfg->dev = dev; cfg->func = func; #if 1 wprintf(L"Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func); wprintf(L" * Vendor: %X Device: %X Class/SubClass/Interface %X/%X/%X\n", cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface); wprintf(L" * Status: %X Command: %X BIST/Type/Lat/CLS: %X/%X/%X/%X\n", cfg->status, cfg->command, cfg->bist, cfg->header_type, cfg->latency_timer, cfg->cache_line_size); #endif switch(cfg->header_type & 0x7F){ case 0: /* normal device */ for(i=0;i<6;i++){ v = pci_read(bus,dev,func,i*4 + 0x10, 4); if(v) { int v2; pci_write(bus,dev,func,i*4 + 0x10, 0xffffffff, 4); v2 = pci_read(bus,dev,func,i*4+0x10, 4) & 0xfffffff0; pci_write(bus,dev,func,i*4 + 0x10, v, 4); v2 = 1 + ~v2; if(v & 1) { // printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff); cfg->base[i] = v & 0xffff; cfg->size[i] = v2 & 0xffff; } else { // printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2); cfg->base[i] = v; cfg->size[i] = v2; } } else { cfg->base[i] = 0; cfg->size[i] = 0; } } v = pci_read(bus,dev,func,0x3c,1); cfg->irq = (v == 0xff ? 0 : v); wprintf(L" * Interrupt Line: %X\n",cfg->irq); break; case 1: wprintf(L" * PCI <-> PCI Bridge\n"); break; default: wprintf(L" * Unknown Header Type\n"); } return 0; } bool pci_find(word vendor_id, word device_id, pci_cfg_t* cfg) { word bus, dev; for (bus = 0; bus < 255; bus++) { for(dev = 0;dev < 32; dev++) { if (pci_probe(bus, dev, 0, cfg)) continue; if (cfg->vendor_id == vendor_id && cfg->device_id == device_id) return true; } } return false; }