blob: 1a6fb7c9094269b47b1184dc7b643ec6cd6aab7e [file] [log] [blame]
/*
* cbdump.c - dump cardbus bridge registers
*
* Copyright (C) 2003 Russell King.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Build instructions:
*
* gcc -O2 -o cbdump cbdump.c -lpci
*/
#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <pci/pci.h>
struct dump_data {
const char *name;
unsigned char offset;
unsigned char size;
};
static void
__dump_memory(void *mem, const struct dump_data *d, int num)
{
int i;
for (i = 0; i < num; i++, d++) {
u32 val = 0xa5a5a5a5;
void *p = (void *) ((unsigned long) mem + d->offset);
switch (d->size) {
case 1: val = *(u8 *)p; break;
case 2: val = *(u16 *)p; break;
case 4: val = *(u32 *)p; break;
}
printf(" %-31s[%02x] : 0x%0*x\n", d->name,
d->offset, d->size * 2, val);
}
}
#define dump_memory(m,d) \
__dump_memory(m,d,sizeof(d)/sizeof(struct dump_data))
static void
__dump_config(struct pci_dev *dev, const struct dump_data *d, int num)
{
int i;
for (i = 0; i < num; i++, d++) {
u32 val = 0xa5a5a5a5;
switch (d->size) {
case 1:
val = pci_read_byte(dev, d->offset);
break;
case 2:
val = pci_read_word(dev, d->offset);
break;
case 4:
val = pci_read_long(dev, d->offset);
break;
}
printf(" %-31s[%02x] : 0x%0*x\n", d->name,
d->offset, d->size * 2, val);
}
}
#define dump_config(m,d) \
__dump_config(m,d,sizeof(d)/sizeof(struct dump_data))
static const struct dump_data cb_data[] = {
{ "CB_SOCKET_EVENT", 0x00, 4 },
{ "CB_SOCKET_MASK", 0x04, 4 },
{ "CB_SOCKET_STATE", 0x08, 4 },
{ "CB_SOCKET_FORCE", 0x0c, 4 },
{ "CB_SOCKET_CONTROL", 0x10, 4 },
{ "CB_SOCKET_POWER", 0x20, 4 },
};
static void dump_cb(void *mem)
{
printf(" -- cardbus registers\n");
dump_memory(mem, cb_data);
}
static const struct dump_data exca_data[] = {
{ "I365_IDENT", 0x00, 1 },
{ "I365_STATUS", 0x01, 1 },
{ "I365_POWER", 0x02, 1 },
{ "I365_INTCTL", 0x03, 1 },
{ "I365_CSC", 0x04, 1 },
{ "I365_CSCINT", 0x05, 1 },
{ "I365_ADDRWIN", 0x06, 1 },
{ "I365_IOCTL", 0x07, 1 },
{ "I365_GENCTL", 0x16, 2 },
{ "I365_GBLCTL", 0x1e, 2 },
{ "I365_IO0_START", 0x08, 2 },
{ "I365_IO0_STOP", 0x0a, 2 },
{ "I365_IO1_START", 0x0c, 2 },
{ "I365_IO1_STOP", 0x0e, 2 },
{ "I365_MEM0_START", 0x10, 2 },
{ "I365_MEM0_STOP", 0x12, 2 },
{ "I365_MEM0_OFF", 0x14, 2 },
{ "I365_MEM0_PAGE", 0x40, 1 },
{ "I365_MEM1_START", 0x18, 2 },
{ "I365_MEM1_STOP", 0x1a, 2 },
{ "I365_MEM1_OFF", 0x1c, 2 },
{ "I365_MEM1_PAGE", 0x41, 1 },
{ "I365_MEM2_START", 0x20, 2 },
{ "I365_MEM2_STOP", 0x22, 2 },
{ "I365_MEM2_OFF", 0x24, 2 },
{ "I365_MEM2_PAGE", 0x42, 1 },
{ "I365_MEM3_START", 0x28, 2 },
{ "I365_MEM3_STOP", 0x2a, 2 },
{ "I365_MEM3_OFF", 0x2c, 2 },
{ "I365_MEM3_PAGE", 0x43, 1 },
{ "I365_MEM4_START", 0x30, 2 },
{ "I365_MEM4_STOP", 0x32, 2 },
{ "I365_MEM4_OFF", 0x34, 2 },
{ "I365_MEM4_PAGE", 0x44, 1 },
};
static void dump_exca(void *mem)
{
printf(" -- exca registers\n");
dump_memory((void *) ((unsigned long) mem + 0x800), exca_data);
}
static void dump_memspace(struct pci_dev *dev, u32 mem)
{
void *base;
int fd;
fd = open("/dev/mem", O_RDONLY);
if (fd == -1) {
perror("open /dev/mem");
return;
}
base = mmap(NULL, 4096, PROT_READ, MAP_SHARED|MAP_FILE, fd, mem);
if (base == (void *)-1) {
perror("mmap /dev/mem");
close(fd);
return;
}
close(fd);
dump_cb(base);
dump_exca(base);
munmap(base, 4096);
}
static struct dump_data cb_general_data[] = {
{ "Vendor ID", PCI_VENDOR_ID, 2 },
{ "Device ID", PCI_DEVICE_ID, 2 },
{ "PCI command", PCI_COMMAND, 2 },
{ "Base address", PCI_BASE_ADDRESS_0, 4 },
{ "Memory Base 0", PCI_CB_MEMORY_BASE_0, 4 },
{ "Memory Limit 0", PCI_CB_MEMORY_LIMIT_0, 4 },
{ "Memory Base 1", PCI_CB_MEMORY_BASE_1, 4 },
{ "Memory Limit 1", PCI_CB_MEMORY_LIMIT_1, 4 },
{ "IO Base 0", PCI_CB_IO_BASE_0, 4 },
{ "IO Limit 0", PCI_CB_IO_LIMIT_0, 4 },
{ "IO Base 1", PCI_CB_IO_BASE_1, 4 },
{ "IO Limit 1", PCI_CB_IO_LIMIT_1, 4 },
{ "Bridge control", PCI_CB_BRIDGE_CONTROL, 2 },
{ "Subsystem vendor ID", PCI_CB_SUBSYSTEM_VENDOR_ID, 2 },
{ "Subsystem device ID", PCI_CB_SUBSYSTEM_ID, 2 },
{ "Legacy mode base", PCI_CB_LEGACY_MODE_BASE, 2 },
};
static const struct dump_data ti_data[] = {
{ "System control", 0x80, 4 },
{ "IRQ Mux", 0x8c, 4 },
{ "Retry", 0x90, 1 },
{ "Card control", 0x91, 1 },
{ "Device control", 0x92, 1 },
{ "Diagnostic", 0x93, 1 },
};
static const struct dump_data rl5c475_data[] = {
{ "System configuration", 0x80, 2 },
{ "Misc Control", 0x82, 2 },
{ "16-bit Interface Control", 0x84, 2 },
{ "16-bit I/O Timing 0", 0x88, 2 },
{ "16-bit Memory Timing 0", 0x8a, 2 },
{ "DMA Slave", 0x90, 2 },
};
static const struct dump_data rl5c476II_data[] = {
{ "Misc Control 2", 0xa0, 2 },
{ "Misc Control 3", 0xa2, 2 },
{ "Misc Control 4", 0xa4, 2 },
{ "GPIO 1", 0xaa, 1 },
};
static void dump_cardbus(struct pci_dev *dev)
{
char class[256];
char name[256];
u32 base;
printf("%02x:%02x.%x %s: %s\n",
dev->bus, dev->dev, dev->func,
pci_lookup_name(dev->access, class, sizeof(class),
PCI_LOOKUP_CLASS,
pci_read_word(dev, PCI_CLASS_DEVICE), 0, 0, 0),
pci_lookup_name(dev->access, name, sizeof(name),
PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
dev->vendor_id, dev->device_id, 0, 0));
base = pci_read_long(dev, PCI_BASE_ADDRESS_0);
printf(" -- generic cardbus config registers\n");
dump_config(dev, cb_general_data);
if (dev->vendor_id == 0x104c) { /* TI */
printf(" -- TI specific config registers\n");
dump_config(dev, ti_data);
}
if ((dev->vendor_id == 0x1180) &&
(dev->device_id == 0x0475)) { /* Ricoh RL5c475 */
printf(" -- Ricoh RL5c475 specific config registers\n");
dump_config(dev, rl5c475_data);
}
if ((dev->vendor_id == 0x1180) &&
(dev->device_id == 0x0476)) { /* Ricoh RL5c476II */
printf(" -- Ricoh RL5c476II specific config registers\n");
dump_config(dev, rl5c475_data);
dump_config(dev, rl5c476II_data);
}
dump_memspace(dev, base);
printf("\n");
}
int main(int argc, char *argv[])
{
struct pci_access *pa;
struct pci_dev *dev;
pa = pci_alloc();
if (!pa) {
perror("pci_alloc");
return 1;
}
pa->writeable = 0;
pa->buscentric = 0;
pci_init(pa);
pci_scan_bus(pa);
for (dev = pa->devices; dev; dev = dev->next) {
unsigned int header;
header = pci_read_word(dev, PCI_HEADER_TYPE);
header &= ~0x80;
if (header == PCI_HEADER_TYPE_CARDBUS)
dump_cardbus(dev);
}
pci_cleanup(pa);
return 0;
}