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