openblt

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

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