openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

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