Newer
Older
ubixos / src / sys / drivers / pci_pio.c
@hypno hypno on 6 Jul 2002 4 KB *** empty log message ***
/*
 * $Id$
 */

/*
 * Copyright (c) 2002 Johnny Zackrisson. All rights reserved.
 *
 * You are free to do whatever you want with this code.
 */

#include <drivers/pci_pio.h>
#include <config.h>

#ifdef _PCI_SUPPORT_

/*
 * Fill in your shit, recompile and prey.
 */
#define PCI_DEVS 	/* how many devices */
struct pci_device_id_t pci_devices = {
	/* Vendor id, device id, name */ 
	0x0000,0x0000,"Oak Technologies" /* example */
};
#endif /* PCI_DEVS */

/* XXX: these does not belong here */
static void outb(u16 port, u8 data);
static void outw(u16 port, u16 data);
static void outl(u16 port, u32 data);
static u8 inb(u16 port);
static u16 inw(u16 port);
static u32 inl(u16 port);

/*
 * XXX: static? 
 */
int pci_get_type();
int pci_init();
int pci_find_devices(struct pci_conf_t *pci_conf[]);  
int pci_t1_read_config(struct pci_conf_t *pci_conf, unsigned int dev);
int pci_t1_write_config(struct pci_conf_t *pci_conf, unsigned int dev);
int pci_t2_read_config(struct pci_conf_t *pci_conf, unsigned int dev);
int pci_t2_write_config(struct pci_conf_t *pci_conf, unsigned int dev);

int
pci_init()
{
	
	
	return(0);
}

int 
pci_get_type()
{
        int x,t=0;

	outb(PCI_BASE, 0);
	outb(PCI_INDEX_REG, 0);
		
	x = inb(PCI_BASE) + inb(PCI_INDEX_REG); 
	if (x == 0) 
		t = PCI_TYPE_2;
	
	x = inb(PCI_BASE);
	outl(PCI_BASE, BUS_ADDRESS);
	x = inl(PCI_BASE);
	if (x == BUS_ADDRESS) 
		t = PCI_TYPE_1;
	outl(PCI_BASE, x);

	return(t);
}

int 
pci_find_devices(struct pci_conf_t *pci_conf[])  
{
	int dev,i,x;

	x = pci_get_type();

	if (x == PCI_TYPE_1) {
		for (i=0; i<PCI_DEVS; i++) {
			pci_t1_read_config(pci_conf[dev], i);
			if (pci_conf[dev]->vendor_id != 0xffff &&
				pci_conf[dev]->device_id != 0xffff)
				dev++;
		}

		return(0);

	} else if (x == PCI_TYPE_2) {
		for (i=0; i<PCI_DEVS; i++) {
			pci_t2_read_config(pci_conf[dev], i);
			if (pci_conf[dev]->vendor_id != 0xffff &&
				pci_conf[dev]->device_id != 0xffff) 
				dev++;
		}

		return(0);
	} 

	return(-1);
}

/* PCI type 1 access method */

int 
pci_t1_read_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
	unsigned int i;

	dev <<= 11;
	for (i=0; i<64; i++) {
		outl(PCI_BASE, (BUS_ADDRESS+(dev+(i*4))));
		((u32 *)pci_conf)[i] = inl(PCI_T1_INDEX_REG);
	}

	if ((pci_conf->vendor_id == 0xffff) &&
		(pci_conf->device_id == 0xffff)) 
		return(-1);
		
	return(0);
}

int
pci_t1_write_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
	int i;

	/* bit 0-7 index into the conf space */
	dev <<= 11;
	for (i=0; i<64; i++) {
		outl(PCI_BASE, (BUS_ADDRESS+(dev+(i*4))));
		outl(PCI_T1_INDEX_REG, ((u32 *)pci_conf)[i]);
	}

	return(0);
}

/* PCI type 2 access method */

int
pci_t2_read_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
	int 	i,x;
	
	/* bit 7 set to select the PCI configuration space */
	x = (((dev & 7) << 1) | 0xf0);	
	outb(PCI_BASE, x);

	/* bus select? */
	outb(PCI_INDEX_REG, 0);

	for (i=0; i<64; i++) 
		((u32 *)pci_conf)[i] = inl(V_BUS_ADDRESS+((dev<<8)+(i*4)));
			
	outb(PCI_BASE,0);

	return(0);
}

int
pci_t2_write_config(struct pci_conf_t *pci_conf, unsigned int dev)
{
	int i,x;

	/* bit 7 set to select the PCI configuration space */
	x = (((dev & 7) << 1) | 0xf0);	
	outb(PCI_BASE, x);

	/* bus select? */
	outb(PCI_INDEX_REG, 0);
	
	for (i=0; i<64; i++) 
		outl(V_BUS_ADDRESS+((dev<<8)+(i*4)), ((u32 *)pci_conf)[i]);
	
	outb(PCI_BASE, 0);

	return(0);
}


/* XXX: these functions below should be in a nice library. */
/* write data to port */

static void 
outb(u16 port, u8 data) 
{
	__asm__ __volatile__(
		"outb 	%1,%0"
		: 
		: "Nd" 	(port),
		  "a"	(data)
	);
}

static void 
outw(u16 port, u16 data) 
{
	__asm__ __volatile__(
		"outw 	%1,%0"
		: 
		: "Nd" 	(port),
		  "a"	(data)
	);
}

static void 
outl(u16 port, u32 data)
{
	__asm__ __volatile__(
		"outl 	%1,%0"
		: 
		: "Nd" 	(port),
		  "a"	(data)
	);
}


/*  get data from port */

static u8 
inb(u16 port)
{
	u8 ret;

	__asm__ __volatile__(
		"inb	%1,%0"
		: "=a" (ret)
		: "Nd" (port)
	);
	
	return(port);
}

static u16 
inw(u16 port)
{
	u16 ret;

	__asm__ __volatile__(
		"inw	%1,%0"
		: "=a" (ret)
		: "Nd" (port)
	);

	return(ret);
}

static u32 
inl(u16 port)
{
	u32 ret;

	__asm__ __volatile__(
		"inl	%1,%0"
		: "=a" (ret)
		: "Nd" (port)
	);

	return(ret);
}