?? pci_utils.c
字號:
/* * * General PCI utilities. * * Copyright (c) 1999 Richard J.M. Close * Copyright (c) 1999 Pavel Machek <pavel@suse.cz> * Copyright (c) 1999 Jamie Lokier * * Can be freely distributed and used under the terms of the GNU GPL. */#include "pci_utils.h"/********************************************************************************** PCI utilities.**********************************************************************************/// Initialises stuff used by PCI routines in this file.// This must be called prior to using any other routines.void init_pci(void){ modem_found = false; io_cnt = 0; htype0_cnt = 6; pacc = pci_alloc(); pacc->error = die; pci_filter_init(pacc, &filter); pci_init(pacc); scan_devices(); sort_them();}void cleanup_pci (void){ pci_cleanup(pacc);}unsigned int get_pcimodem_irq (void){ return modem_dev->dev->irq;}struct device *scan_device(struct pci_dev *p){ int how_much = 0x40; /* First 64 bytes. */ struct device *d; if (!pci_filter_match(&filter, p)) return NULL; d = xmalloc(sizeof(struct device)); bzero(d, sizeof(*d)); d->dev = p; if (!pci_read_block(p, 0, d->config, how_much)) die("Unable to read %d bytes of configuration space.", how_much); if (how_much < 128 && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS) { /* For cardbus bridges, we need to fetch 64 bytes more to get the full standard header... */ if (!pci_read_block(p, 0, d->config+64, 64)) die("Unable to read cardbus bridge extension data."); how_much = 128; } d->config_cnt = how_much; pci_setup_cache(p, d->config, d->config_cnt); pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE); return d;}voidscan_devices(void){ struct device *d; struct pci_dev *p; pci_scan_bus(pacc); for(p=pacc->devices; p; p=p->next) if (d = scan_device(p)) { d->next = first_dev; first_dev = d; }}intcheck_root(void){ int is_root = -1; if (is_root < 0) is_root = !geteuid(); return is_root;}intconfig_fetch(struct device *d, unsigned int pos, unsigned int len){ if (pos + len < d->config_cnt) return 1; if (pacc->method != PCI_ACCESS_DUMP && !check_root()) return 0; return pci_read_block(d->dev, pos, d->config + pos, len);}/* Config space accesses */inline byteget_conf_byte(struct device *d, unsigned int pos){ return d->config[pos];}wordget_conf_word(struct device *d, unsigned int pos){ return d->config[pos] | (d->config[pos+1] << 8);}unsigned longget_conf_long(struct device *d, unsigned int pos){ return d->config[pos] | (d->config[pos+1] << 8) | (d->config[pos+2] << 16) | (d->config[pos+3] << 24);}/* Sorting */intcompare_them(const void *A, const void *B){ const struct pci_dev *a = (*(const struct device **)A)->dev; const struct pci_dev *b = (*(const struct device **)B)->dev; if (a->bus < b->bus) return -1; if (a->bus > b->bus) return 1; if (a->dev < b->dev) return -1; if (a->dev > b->dev) return 1; if (a->func < b->func) return -1; if (a->func > b->func) return 1; return 0;}voidsort_them(void){ struct device **index, **h, **last_dev; int cnt; struct device *d; cnt = 0; for(d=first_dev; d; d=d->next) cnt++; h = index = alloca(sizeof(struct device *) * cnt); for(d=first_dev; d; d=d->next) *h++ = d; qsort(index, cnt, sizeof(struct device *), compare_them); last_dev = &first_dev; h = index; while (cnt--) { *last_dev = *h; last_dev = &(*h)->next; h++; } *last_dev = NULL;}/* Normal output */voidshow_bases(struct device *d, int cnt){ struct pci_dev *p = d->dev; word cmd = get_conf_word(d, PCI_COMMAND); int i; for(i=0; i<cnt; i++) { pciaddr_t pos = p->base_addr[i]; u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i); if (flg == 0xffffffff) flg = 0; if (!pos && !flg) continue; printf("\tRegion %d: ", i); if (pos && !flg) /* Reported by the OS, but not by the device */ { printf("[virtual] "); flg = pos; } if (flg & PCI_BASE_ADDRESS_SPACE_IO) { pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK; printf("I/O ports at "); if (a) { printf(IO_FORMAT, a); } else if (flg & PCI_BASE_ADDRESS_IO_MASK) printf("<ignored>"); else printf("<unassigned>"); if (!(cmd & PCI_COMMAND_IO)) printf(" [disabled]"); } else { int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK; pciaddr_t a = pos & PCI_ADDR_MEM_MASK; int done = 0; u32 z = 0; printf("Memory at "); if (t == PCI_BASE_ADDRESS_MEM_TYPE_64) { if (i >= cnt - 1) { printf("<invalid-64bit-slot>\n"); done = 1; } else { i++; z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i); if (buscentric_view) { if (a || z) printf("%08x" ADDR_FORMAT, z, a); else printf("<unassigned>"); done = 1; } } } if (!done) { if (a) printf(ADDR_FORMAT, a); else printf(((flg & PCI_BASE_ADDRESS_MEM_MASK) || z) ? "<ignored>" : "<unassigned>"); } printf(" (%s, %sprefetchable)", (t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" : (t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" : (t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3", (flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-"); if (!(cmd & PCI_COMMAND_MEMORY)) printf(" [disabled]"); } putchar('\n'); }}voidshow_htype0(struct device *d){ unsigned long rom = d->dev->rom_base_addr; show_bases(d, htype0_cnt); if (rom & 1) printf("\tExpansion ROM at %08lx%s\n", rom & PCI_ROM_ADDRESS_MASK, (rom & PCI_ROM_ADDRESS_ENABLE) ? "" : " [disabled]"); if (get_conf_word(d, PCI_STATUS) & PCI_STATUS_CAP_LIST) { int where = get_conf_byte(d, PCI_CAPABILITY_LIST); while (where) { int id, next, cap; printf("\tCapabilities: "); if (!config_fetch(d, where, 4)) { puts("<available only to root>"); break; } id = get_conf_byte(d, where + PCI_CAP_LIST_ID); next = get_conf_byte(d, where + PCI_CAP_LIST_NEXT); cap = get_conf_word(d, where + PCI_CAP_FLAGS); printf("[%02x] ", where); if (id == 0xff) { printf("<chain broken>\n"); break; } switch (id) { case PCI_CAP_ID_PM: printf("Power Management version %d\n", cap & PCI_PM_CAP_VER_MASK); break; case PCI_CAP_ID_AGP: break; default: printf("#%02x [%04x]", id, cap); } where = next; } }}struct bus *find_bus(struct bridge *b, unsigned int n){ struct bus *bus; for(bus=b->first_bus; bus; bus=bus->sibling) if (bus->number == n) break; return bus;}struct bus *new_bus(struct bridge *b, unsigned int n){ struct bus *bus = xmalloc(sizeof(struct bus)); bus = xmalloc(sizeof(struct bus)); bus->number = n; bus->sibling = b->first_bus; bus->first_dev = NULL; bus->last_dev = &bus->first_dev; b->first_bus = bus; return bus;}voidinsert_dev(struct device *d, struct bridge *b){ struct pci_dev *p = d->dev; struct bus *bus; if (! (bus = find_bus(b, p->bus))) { struct bridge *c; for(c=b->child; c; c=c->next) if (c->secondary <= p->bus && p->bus <= c->subordinate) return insert_dev(d, c); bus = new_bus(b, p->bus); } /* Simple insertion at the end _does_ guarantee the correct order as the * original device list was sorted by (bus, devfn) lexicographically * and all devices on the new list have the same bus number. */ *bus->last_dev = d; bus->last_dev = &d->next; d->next = NULL;}/* Bus mapping mode */voiddo_map_bridges(int bus, int min, int max){ struct bus_info *bi = bus_info + bus; struct bus_bridge *b; bi->guestbook = 1; for(b=bi->bridges; b; b=b->next) { if (bus_info[b->first].guestbook) b->bug = 1; else if (b->first < min || b->last > max) b->bug = 2; else { bus_info[b->first].via = b; do_map_bridges(b->first, b->first, b->last); } }}/* Show hexadecimal dump of first 64 bytes of the PCI configuration space (the standard header). Useful for debugging of drivers and lspci itself. */voidshow_pcihex_dump(struct device *d){ unsigned int i; printf("Command reg: "); printf(" %02x", get_conf_byte(d, 5)); printf(" %02x", get_conf_byte(d, 4)); putchar('\t'); printf("Status reg: "); printf(" %02x", get_conf_byte(d, 7)); printf(" %02x", get_conf_byte(d, 6)); putchar('\n'); /* Note! the byte order is lsb msb */ printf("Base address regs: "); for(i=0x10; i<0x24; i++){ printf(" %02x", get_conf_byte(d, i)); } putchar('\n');}/* Find any known any Lucent modems. */int find_modem(void){ struct device *d; int i; for(d=first_dev; d; d=d->next) { struct pci_dev *p = d->dev; /* Only cards with vendor ID = Lucent!. */ if (p->vendor_id == 0x11c1) { modem_dev = d; modem_found = true; io_cnt = 0; /* Record I/O addresses. */ for(i=0; i<htype0_cnt; i++){ pciaddr_t pos = p->base_addr[i]; u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i); if (flg == 0xffffffff) flg = 0; if (!pos && !flg) continue; if (flg & PCI_BASE_ADDRESS_SPACE_IO) { io_address[i] = pos & PCI_BASE_ADDRESS_IO_MASK; io_length[i] = (io_address[i] < 0x3f8) ? 8 : 256; io_cnt = i; } } } } return modem_found;}// Show any found modem.void show_pcimodem(void){ int c; struct pci_dev *p = modem_dev->dev; byte classbuf[128], devbuf[128]; unsigned int irq = p->irq; byte latency = get_conf_byte( modem_dev, PCI_LATENCY_TIMER); word status = get_conf_word( modem_dev, PCI_STATUS); word cmd = get_conf_word( modem_dev, PCI_COMMAND); byte max_lat, min_gnt; word subsys_v, subsys_d; char ssnamebuf[256]; printf("%02x:%02x.%x %s: %s", p->bus, p->dev, p->func, pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, get_conf_word( modem_dev, PCI_CLASS_DEVICE), 0), pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id)); if (c = get_conf_byte( modem_dev, PCI_REVISION_ID)) printf(" (rev %02x)", c); if (c = get_conf_byte( modem_dev, PCI_CLASS_PROG)) printf(" (prog-if %02x)", c); putchar('\n'); // Only cards with device ID 0x44* are mars chipset based. if ((p->device_id & 0xfff0) == 0x440) printf("Mars chipset detected.\n"); else printf("Warning: your modem does not have a mars chipset.\n"); max_lat = get_conf_byte( modem_dev, PCI_MAX_LAT); min_gnt = get_conf_byte( modem_dev, PCI_MIN_GNT); subsys_v = get_conf_word( modem_dev, PCI_SUBSYSTEM_VENDOR_ID); subsys_d = get_conf_word( modem_dev, PCI_SUBSYSTEM_ID); if (subsys_v && subsys_v != 0xffff) printf("\tSubsystem: %s\n", pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, subsys_v, subsys_d)); printf("\tFlags: "); if (cmd & PCI_COMMAND_MASTER) printf("bus master, "); if (cmd & PCI_COMMAND_VGA_PALETTE) printf("VGA palette snoop, "); if (cmd & PCI_COMMAND_WAIT) printf("stepping, "); if (cmd & PCI_COMMAND_FAST_BACK) printf("fast Back2Back, "); if (status & PCI_STATUS_66MHZ) printf("66Mhz, "); if (status & PCI_STATUS_UDF) printf("user-definable features, "); printf("%s devsel", ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" : ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" : ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??"); if (cmd & PCI_COMMAND_MASTER) printf(", latency %d", latency); if (irq) printf(", IRQ " IRQ_FORMAT, irq); putchar('\n'); show_htype0( modem_dev);}void redisplay_modem_regs(void) { /* Re-scan device. */ printf ("Registers now contain:\n"); pci_scan_bus(pacc); modem_dev = scan_device(modem_dev->dev); /* Show the hex. */ show_pcihex_dump(modem_dev); }voidset_modem_cont_reg(void) { /* value input by user. */ int input = 0; /* CR input after first char. */ char trash; /* Allow user to set control register. */ printf ("Set control register (value in hex): "); scanf ("%x%c", &input, &trash); printf ("Writing %x to control register.\n", input); /* command register is at address 04. */ pci_write_word(modem_dev->dev, 0x04, input); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -