/branches/dd/uspace/srv/pci/pci/pci_bus.h |
---|
File deleted |
\ No newline at end of file |
/branches/dd/uspace/srv/pci/pci/pci.c |
---|
File deleted |
/branches/dd/uspace/srv/pci/pci/Makefile |
---|
File deleted |
/branches/dd/uspace/srv/pci/pci/pci.h |
---|
File deleted |
/branches/dd/uspace/srv/pci/pci/pci_regs.h |
---|
File deleted |
/branches/dd/uspace/srv/pci/pci/main.c |
---|
File deleted |
/branches/dd/uspace/srv/pci/pci/pci_conf.h |
---|
File deleted |
\ No newline at end of file |
/branches/dd/uspace/srv/pci/pci/psycho.c |
---|
File deleted |
\ No newline at end of file |
/branches/dd/uspace/srv/pci/pci.h |
---|
0,0 → 1,97 |
#ifndef PCI_H |
#define PCI_H |
//#include <arch/types.h> |
#include <libadt/list.h> |
#include <stdio.h> |
struct pci_drv; |
struct pci_dev; |
struct pci_bus; |
struct pci_drv_ops; |
typedef struct pci_drv pci_drv_t; |
typedef struct pci_dev pci_dev_t; |
typedef struct pci_bus pci_bus_t; |
typedef struct pci_drv_ops pci_drv_ops_t; |
struct pci_drv { |
link_t link; |
int vendor_id; |
int device_id; |
pci_drv_ops_t *ops; |
}; |
struct pci_dev{ |
link_t link; |
pci_bus_t *bus; |
int dev; |
int fn; |
int vendor_id; |
int device_id; |
pci_drv_t *driver; |
}; |
struct pci_drv_ops { |
int (*add_device)(pci_dev_t *dev); |
}; |
struct pci_bus { |
link_t link; |
int num; |
// architecture-specific usage |
void *data; |
}; |
void pci_bus_register(pci_bus_t *bus); |
void pci_device_register(pci_dev_t *dev); |
void pci_driver_register(pci_drv_t *drv); |
void pci_bus_scan(pci_bus_t *bus); |
static inline pci_bus_t* pci_alloc_bus() |
{ |
pci_bus_t *bus = (pci_bus_t *)malloc(sizeof(pci_bus_t)); |
link_initialize(&bus->link); |
bus->num = 0; |
bus->data = NULL; |
return bus; |
} |
// arch. spec. initialization of pci bus structure - of its data member |
void pci_init_bus_data(pci_bus_t *bus, pci_bus_t *parent); |
static inline void pci_init_bus(pci_bus_t *bus, pci_bus_t *parent, int bus_num) |
{ |
bus->num = bus_num; |
pci_init_bus_data(bus, parent); |
} |
static inline void pci_free_bus(pci_bus_t *bus) |
{ |
free(bus); |
} |
static inline pci_dev_t* pci_alloc_dev() |
{ |
pci_dev_t *dev = (pci_dev_t *)malloc(sizeof(pci_dev_t)); |
bzero(dev, sizeof(pci_dev_t)); |
link_initialize(&dev->link); |
return dev; |
} |
static inline void pci_init_dev(pci_dev_t *dev, pci_bus_t *bus, int devnum, int fn) |
{ |
dev->bus = bus; |
dev->dev = devnum; |
dev->fn = fn; |
} |
static inline void pci_free_dev(pci_dev_t *dev) |
{ |
free(dev); |
} |
#endif |
/branches/dd/uspace/srv/pci/pci_regs.h |
---|
0,0 → 1,78 |
#ifndef PCI_REGS_H |
#define PCI_REGS_H |
// Header types |
#define PCI_HEADER_TYPE_DEV 0 |
#define PCI_HEADER_TYPE_BRIDGE 1 |
#define PCI_HEADER_TYPE_CARDBUS 2 |
// Header type 0 and 1 |
#define PCI_VENDOR_ID 0x00 |
#define PCI_DEVICE_ID 0x02 |
#define PCI_COMMAND 0x04 |
#define PCI_STATUS 0x06 |
#define PCI_REVISION_ID 0x08 |
#define PCI_PROG_IF 0x09 |
#define PCI_SUB_CLASS 0x0A |
#define PCI_BASE_CLASS 0x0B |
#define PCI_CACHE_LINE_SIZE 0x0C |
#define PCI_LATENCY_TIMER 0x0D |
#define PCI_HEADER_TYPE 0x0E |
#define PCI_BIST 0x0F |
#define PCI_BASE_ADDR_0 0x10 |
#define PCI_BASE_ADDR_1 0x14 |
// Header type 0 |
#define PCI_BASE_ADDR_2 0x18 |
#define PCI_BASE_ADDR_3 0x1B |
#define PCI_BASE_ADDR_4 0x20 |
#define PCI_BASE_ADDR_5 0x24 |
#define PCI_CARDBUS_CIS_PTR 0x28 |
#define PCI_SUBSYSTEM_VENDOR_ID 0x2C |
#define PCI_SUBSYSTEM_ID 0x2E |
#define PCI_EXP_ROM_BASE 0x30 |
#define PCI_CAP_PTR 0x34 |
#define PCI_INT_LINE 0x3C |
#define PCI_INT_PIN 0x3D |
#define PCI_MIN_GNT 0x3E |
#define PCI_MAX_LAT 0x3F |
// Header type 1 |
#define PCI_BRIDGE_PRIM_BUS_NUM 0x18 |
#define PCI_BRIDGE_SEC_BUS_NUM 0x19 |
#define PCI_BRIDGE_SUBORD_BUS_NUM 0x1A |
#define PCI_BRIDGE_SEC_LATENCY_TIMER 0x1B |
#define PCI_BRIDGE_IO_BASE 0x1C |
#define PCI_BRIDGE_IO_LIMIT 0x1D |
#define PCI_BRIDGE_SEC_STATUS 0x1E |
#define PCI_BRIDGE_MEMORY_BASE 0x20 |
#define PCI_BRIDGE_MEMORY_LIMIT 0x22 |
#define PCI_BRIDGE_PREF_MEMORY_BASE 0x24 |
#define PCI_BRIDGE_PREF_MEMORY_LIMIT 0x26 |
#define PCI_BRIDGE_PREF_MEMORY_BASE_UP 0x28 |
#define PCI_BRIDGE_PREF_MEMORY_LIMIT_UP 0x2C |
#define PCI_BRIDGE_IO_BASE_UP 0x30 |
#define PCI_BRIDGE_IO_LIMIT_UP 0x32 |
#define PCI_BRIDGE_EXP_ROM_BASE 0x38 |
#define PCI_BRIDGE_INT_LINE 0x3C |
#define PCI_BRIDGE_INT_PIN 0x3D |
#define PCI_BRIDGE_CTL 0x3E |
/* // from psycho spec. |
Reserved 0x28-0x2F n/a |
Expansion ROM 0x30 4 bytes |
Reserved 0x34-0x3B n/a |
Interrupt Line 0x3C 1 byte |
Interrupt Pin 0x3D 1 byte |
MIN_GNT 0x3E 1 byte |
MAX_LAT 0x3F 1 byte*/ |
#endif |
/branches/dd/uspace/srv/pci/main.c |
---|
0,0 → 1,19 |
#include <stdio.h> |
#include <stdlib.h> |
#include "pci.h" |
#include "pci_bus.h" |
int main(int argc, char **argv) |
{ |
printf("PCI bus driver\n"); |
if (!pci_bus_init()) { |
printf("PCI bus initialization failed.\n"); |
return 1; |
} |
// TODO: write driver of some device and initialize it here |
return 0; |
} |
/branches/dd/uspace/srv/pci/pci_conf.h |
---|
0,0 → 1,10 |
#ifndef PCI_CONF_H |
#define PCI_CONF_H |
#include "pci.h" |
uint8_t pci_conf_read_8(pci_dev_t *dev, int reg); |
uint16_t pci_conf_read_16(pci_dev_t *dev, int reg); |
uint32_t pci_conf_read_32(pci_dev_t *dev, int reg); |
#endif |
/branches/dd/uspace/srv/pci/psycho.c |
---|
0,0 → 1,173 |
#include <malloc.h> |
#include <assert.h> |
#include <unistd.h> |
#include <ddi.h> |
#include <libarch/ddi.h> |
#include <stdio.h> |
#include <futex.h> |
#include "pci.h" |
#include "pci_bus.h" |
#define PCI_CONF_OFFSET 0x001000000 |
#define PCI_CONF_SIZE 0x001000000 |
/* |
* virtual address of specified PCI configuration register: |
* conf_base ... base address of configuration address space |
* bus ... bus number |
* dev ... device number (0 - 31) |
* fn ... function number (0 - 7) |
* reg ... register number (register's position within PCI configuration header) |
**/ |
#define CONF_ADDR(conf_base, bus, dev, fn, reg) ((void *)(conf_base + ((bus << 16) | (dev << 11) | (fn << 8) | reg))) |
static atomic_t pci_conf_futex = FUTEX_INITIALIZER; |
static long u2p_space_cnt = 0; |
static long *u2p_bases; |
/* virtual addresses of PCI configuration spaces */ |
static void **conf_bases; |
static int psycho_init(); |
static void u2p_bases_init(); |
static void psycho_scan(); |
static void * psycho_conf_addr(pci_dev_t *dev, int reg); |
static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len); |
static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len); |
static void * psycho_conf_addr(pci_dev_t *dev, int reg) |
{ |
return CONF_ADDR(dev->bus->data, dev->bus->num, dev->dev, dev->fn, reg); |
} |
static void psycho_scan() |
{ |
printf("PCI: psycho_scan\n"); |
int i, num; |
for (i = 0; i < u2p_space_cnt; i++) { |
for (num = 0; num <= 0x80; num += 0x80) { |
pci_bus_t *bus = pci_alloc_bus(); |
bus->num = num; |
bus->data = conf_bases[i]; |
pci_bus_register(bus); |
pci_bus_scan(bus); |
} |
} |
} |
static int psycho_init() |
{ |
printf("PCI: starting psycho initialization.\n"); |
u2p_bases_init(); |
conf_bases = (void **)malloc(u2p_space_cnt * sizeof(void *)); |
int i, error; |
for (i = 0; i < u2p_space_cnt; i++) { |
if (error = pio_enable((void *)(u2p_bases[i] + PCI_CONF_OFFSET), PCI_CONF_SIZE, &(conf_bases[i]))) { |
printf("PCI: failed to enable psycho conf. adr. space num. %d. (error %d)\n", i, error); |
return 0; |
} |
} |
return 1; |
} |
static void u2p_bases_init() |
{ |
// TODO: write this more generally - get this information from firmware (using kernel + sysinfo) |
u2p_space_cnt = 2; |
//u2p_space_cnt = 1; |
u2p_bases = (void **)malloc(u2p_space_cnt * sizeof(void *)); |
u2p_bases[0] = 0x1c800000000; |
u2p_bases[1] = 0x1ca00000000; |
} |
uint8_t pci_conf_read_8(pci_dev_t *dev, int reg) |
{ |
uint8_t res; |
futex_down(&pci_conf_futex); |
psycho_conf_read(dev, reg, &res, sizeof(uint8_t)); |
futex_up(&pci_conf_futex); |
return res; |
} |
uint16_t pci_conf_read_16(pci_dev_t *dev, int reg) |
{ |
uint16_t res; |
futex_down(&pci_conf_futex); |
psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint16_t)); |
futex_up(&pci_conf_futex); |
return res; |
} |
uint32_t pci_conf_read_32(pci_dev_t *dev, int reg) |
{ |
uint32_t res; |
futex_down(&pci_conf_futex); |
psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint32_t)); |
futex_up(&pci_conf_futex); |
return res; |
} |
static inline uint16_t invert_endianess_16(uint16_t x) |
{ |
return (x & 0xFF) << 8 | (x >> 8); |
} |
static inline uint32_t invert_endianess_32(uint32_t x) |
{ |
return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24); |
} |
static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len) |
{ |
switch (len) { |
case 1: |
buf[0] = pio_read_8(psycho_conf_addr(d, reg)); |
break; |
case 2: |
*((uint16_t *)buf) = invert_endianess_16(pio_read_16(psycho_conf_addr(d, reg))); |
break; |
case 4: |
*((uint32_t *)buf) = invert_endianess_32(pio_read_32(psycho_conf_addr(d, reg))); |
break; |
} |
} |
static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len) |
{ |
switch (len) { |
case 1: |
pio_write_8(psycho_conf_addr(d, reg), buf[0]); |
break; |
case 2: |
pio_write_16(psycho_conf_addr(d, reg), invert_endianess_16(*((uint16_t *)buf))); |
break; |
case 4: |
pio_write_32(psycho_conf_addr(d, reg), invert_endianess_32(*((uint32_t *)buf))); |
break; |
} |
} |
/* pci bus structure initialization */ |
void pci_init_bus_data(pci_bus_t *bus, pci_bus_t *parent) |
{ |
if (parent != NULL) { |
bus->data = parent->data; |
} |
} |
int pci_bus_init() |
{ |
if(!psycho_init()) { |
return 0; |
} |
psycho_scan(); |
return 1; |
} |
void pci_bus_clean() |
{ |
free(u2p_bases); |
free(conf_bases); |
} |
/branches/dd/uspace/srv/pci/pci_bus.h |
---|
0,0 → 1,7 |
#ifndef PCI_BUS_H |
#define PCI_BUS_H |
int pci_bus_init(); |
void pci_bus_clean(); |
#endif |
/branches/dd/uspace/srv/pci/pci.c |
---|
0,0 → 1,155 |
#include <futex.h> |
#include <assert.h> |
#include "pci.h" |
#include "pci_bus.h" |
#include "pci_regs.h" |
#include "pci_conf.h" |
LIST_INITIALIZE(devices_list); |
LIST_INITIALIZE(buses_list); |
LIST_INITIALIZE(drivers_list); |
static atomic_t pci_bus_futex = FUTEX_INITIALIZER; |
static int pci_match(pci_drv_t *drv, pci_dev_t *dev); |
static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev); |
static void pci_lookup_driver(pci_dev_t *dev); |
static void pci_lookup_devices(pci_drv_t *drv); |
// TODO: think about locking |
void pci_bus_scan(pci_bus_t *bus) |
{ |
pci_dev_t *dev = pci_alloc_dev(); |
pci_bus_t *child_bus = NULL; |
int dnum, fnum; |
bool multi; |
uint8_t header_type; |
printf("PCI: scanning bus number %d\n", bus->num); |
for (dnum = 0; dnum < 4/*256*/; dnum++) { |
multi = true; |
for (fnum = 0; multi && fnum < 8; fnum++) { |
pci_init_dev(dev, bus, dnum, fnum); |
dev->vendor_id = pci_conf_read_16(dev, PCI_VENDOR_ID); |
dev->device_id = pci_conf_read_16(dev, PCI_DEVICE_ID); |
if (dev->vendor_id == 0xFFFF) { |
continue; // device is not present, go on scanning the bus |
} |
header_type = pci_conf_read_8(dev, PCI_HEADER_TYPE); |
if (fnum == 0) { |
multi = header_type >> 7; // is the device multifunction? |
} |
header_type = header_type & 0x7F; // clear the multifunction bit |
printf("PCI: adding new device %d : %d", dnum, fnum); |
printf(" - vendor = %x, device = %x.\n", dev->vendor_id, dev->device_id); |
pci_device_register(dev); |
dev = pci_alloc_dev(); // alloc new aux. dev. structure |
if (header_type == PCI_HEADER_TYPE_BRIDGE || header_type == PCI_HEADER_TYPE_CARDBUS ) { |
if (dnum != 0 && fnum != 0) { |
child_bus = pci_alloc_bus(); |
pci_init_bus(child_bus, bus, pci_conf_read_8(dev, PCI_BRIDGE_SEC_BUS_NUM)); |
pci_bus_register(child_bus); |
pci_bus_scan(child_bus); |
} |
} |
} |
} |
if (dev->vendor_id == 0xFFFF) { |
pci_free_dev(dev); // free the auxiliary device structure |
} |
} |
/* |
* Usage: pci_bus_futex must be down. |
*/ |
static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev) |
{ |
assert(dev->driver == NULL); |
if (drv->ops->add_device(dev)) { |
dev->driver = drv; |
return 1; |
} |
return 0; |
} |
/* |
* Usage: pci_bus_futex must be down. |
*/ |
static void pci_lookup_driver(pci_dev_t *dev) |
{ |
link_t *item = drivers_list.next; |
pci_drv_t *drv = NULL; |
while (item != &drivers_list) { |
drv = list_get_instance(item, pci_drv_t, link); |
if (pci_match(drv, dev) && pci_pass_dev(drv, dev)) { |
break; |
} |
item = item->next; |
} |
} |
/* |
* Usage: pci_bus_futex must be down. |
*/ |
static void pci_lookup_devices(pci_drv_t *drv) |
{ |
link_t *item = devices_list.next; |
pci_dev_t *dev = NULL; |
while (item != &devices_list) { |
dev = list_get_instance(item, pci_dev_t, link); |
if (dev->driver == NULL && pci_match(drv, dev)) { |
pci_pass_dev(drv, dev); |
} |
item = item->next; |
} |
} |
static int pci_match(pci_drv_t *drv, pci_dev_t *dev) |
{ |
return drv->vendor_id == dev->vendor_id && drv->device_id == dev->vendor_id; |
} |
void pci_bus_register(pci_bus_t *bus) |
{ |
futex_down(&pci_bus_futex); |
// add the device to the list of pci devices |
list_append(&(bus->link), &buses_list); |
futex_up(&pci_bus_futex); |
} |
void pci_device_register(pci_dev_t *dev) |
{ |
futex_down(&pci_bus_futex); |
// add the device to the list of pci devices |
list_append(&(dev->link), &devices_list); |
// try to find suitable driver for the device and pass the device to it |
pci_lookup_driver(dev); |
futex_up(&pci_bus_futex); |
} |
void pci_driver_register(pci_drv_t *drv) |
{ |
futex_down(&pci_bus_futex); |
list_append(&(drv->link), &drivers_list); |
// try to find compatible devices |
pci_lookup_devices(drv); |
futex_up(&pci_bus_futex); |
} |
/branches/dd/uspace/srv/pci/Makefile |
---|
0,0 → 1,84 |
# |
# Copyright (c) 2005 Martin Decky |
# All rights reserved. |
# |
# Redistribution and use in source and binary forms, with or without |
# modification, are permitted provided that the following conditions |
# are met: |
# |
# - Redistributions of source code must retain the above copyright |
# notice, this list of conditions and the following disclaimer. |
# - Redistributions in binary form must reproduce the above copyright |
# notice, this list of conditions and the following disclaimer in the |
# documentation and/or other materials provided with the distribution. |
# - The name of the author may not be used to endorse or promote products |
# derived from this software without specific prior written permission. |
# |
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
# |
## Setup toolchain |
# |
LIBC_PREFIX = ../../lib/libc |
SOFTINT_PREFIX = ../../lib/softint |
include $(LIBC_PREFIX)/Makefile.toolchain |
CFLAGS += -I../libipc/include |
LIBS = $(LIBC_PREFIX)/libc.a |
## Sources |
# |
OUTPUT = pci |
SOURCES = \ |
main.c \ |
pci.c |
ifeq ($(PROCESSOR), us) |
SOURCES += psycho.c |
endif |
CFLAGS += -D$(UARCH) |
OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) |
.PHONY: all clean depend disasm |
all: $(OUTPUT) $(OUTPUT).disasm |
-include Makefile.depend |
clean: |
-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS) |
depend: |
$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend |
$(OUTPUT): $(OBJECTS) $(LIBS) |
$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map |
disasm: $(OUTPUT).disasm |
$(OUTPUT).disasm: $(OUTPUT) |
$(OBJDUMP) -d $< >$@ |
%.o: %.S |
$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@ |
%.o: %.s |
$(AS) $(AFLAGS) $< -o $@ |
%.o: %.c |
$(CC) $(DEFS) $(CFLAGS) -c $< -o $@ |