pci.c (3257B)
1 /* $Id$ 2 ** 3 ** Copyright 1999 Brian J. Swetland. All rights reserved. 4 ** Distributed under the terms of the OpenBLT License 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <fcntl.h> 10 11 #include <i386/io.h> 12 13 #include "pci.h" 14 15 typedef struct 16 { 17 uchar reg:8; 18 uchar func:3; 19 uchar dev:5; 20 uchar bus:8; 21 uchar rsvd:7; 22 uchar enable:1; 23 } confadd; 24 25 uint32 pci_read(int bus, int dev, int func, int reg, int bytes) 26 { 27 uint32 base; 28 29 union { 30 confadd c; 31 uint32 n; 32 } u; 33 34 u.c.enable = 1; 35 u.c.rsvd = 0; 36 u.c.bus = bus; 37 u.c.dev = dev; 38 u.c.func = func; 39 u.c.reg = reg & 0xFC; 40 41 outl(u.n,0xCF8); 42 43 base = 0xCFC + (reg & 0x03); 44 45 switch(bytes){ 46 case 1: return inb(base); 47 case 2: return inw(base); 48 case 4: return inl(base); 49 default: return 0; 50 } 51 } 52 53 void pci_write(int bus, int dev, int func, int reg, uint32 v, int bytes) 54 { 55 uint32 base; 56 57 union { 58 confadd c; 59 uint32 n; 60 } u; 61 62 u.c.enable = 1; 63 u.c.rsvd = 0; 64 u.c.bus = bus; 65 u.c.dev = dev; 66 u.c.func = func; 67 u.c.reg = reg & 0xFC; 68 69 base = 0xCFC + (reg & 0x03); 70 outl(u.n,0xCF8); 71 switch(bytes){ 72 case 1: outb(v,base); break; 73 case 2: outw(v,base); break; 74 case 4: outl(v,base); break; 75 } 76 77 } 78 79 int pci_probe(int bus, int dev, int func, pci_cfg *cfg) 80 { 81 uint32 *word = (uint32 *) cfg; 82 uint32 v; 83 int i; 84 for(i=0;i<4;i++){ 85 word[i] = pci_read(bus,dev,func,4*i,4); 86 } 87 if(cfg->vendor_id == 0xffff) return 1; 88 89 cfg->bus = bus; 90 cfg->dev = dev; 91 cfg->func = func; 92 #if 0 93 printf("Device Info: /bus/pci/%d/%d/%d\n",bus,dev,func); 94 printf(" * Vendor: %S Device: %S Class/SubClass/Interface %X/%X/%X\n", 95 cfg->vendor_id,cfg->device_id,cfg->base_class,cfg->sub_class,cfg->interface); 96 printf(" * Status: %S Command: %S BIST/Type/Lat/CLS: %X/%X/%X/%X\n", 97 cfg->status, cfg->command, cfg->bist, cfg->header_type, 98 cfg->latency_timer, cfg->cache_line_size); 99 #endif 100 101 switch(cfg->header_type & 0x7F){ 102 case 0: /* normal device */ 103 for(i=0;i<6;i++){ 104 v = pci_read(bus,dev,func,i*4 + 0x10, 4); 105 if(v) { 106 int v2; 107 pci_write(bus,dev,func,i*4 + 0x10, 0xffffffff, 4); 108 v2 = pci_read(bus,dev,func,i*4+0x10, 4) & 0xfffffff0; 109 pci_write(bus,dev,func,i*4 + 0x10, v, 4); 110 v2 = 1 + ~v2; 111 if(v & 1) { 112 // printf(" * Base Register %d IO: %x (%x)\n",i,v&0xfff0,v2&0xffff); 113 cfg->base[i] = v & 0xffff; 114 cfg->size[i] = v2 & 0xffff; 115 } else { 116 // printf(" * Base Register %d MM: %x (%x)\n",i,v&0xfffffff0,v2); 117 cfg->base[i] = v; 118 cfg->size[i] = v2; 119 } 120 } else { 121 cfg->base[i] = 0; 122 cfg->size[i] = 0; 123 } 124 125 } 126 v = pci_read(bus,dev,func,0x3c,1); 127 // if((v != 0xff) && (v != 0)) printf(" * Interrupt Line: %X\n",v); 128 break; 129 case 1: 130 // printf(" * PCI <-> PCI Bridge\n"); 131 break; 132 default: 133 // printf(" * Unknown Header Type\n"); 134 } 135 return 0; 136 } 137 138 int pci_find(pci_cfg *cfg, uint16 vendor_id, uint16 device_id) 139 { 140 int bus,dev,func; 141 142 for(bus=0;bus<255;bus++){ 143 for(dev=0;dev<32;dev++) { 144 if(pci_probe(bus,dev,0,cfg)) continue; 145 if((cfg->vendor_id == vendor_id) && 146 (cfg->device_id == device_id)) return 0; 147 if(cfg->header_type & 0x80){ 148 for(func=1;func<8;func++){ 149 if(!pci_probe(bus,dev,func,cfg) && 150 (cfg->vendor_id == vendor_id) && 151 (cfg->device_id == device_id)) return 0; 152 } 153 } 154 } 155 } 156 } 157