?? pciregions.c
字號:
/* * pciregions.c -- a module that prints address regions of PCI devices * * $Id: pciregions.c,v 1.9 2001/03/16 11:30:23 rubini Exp $ * * Copyright (C) 1997,2001 rubini@linux.it (Alessandro Rubini) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#include <linux/config.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/pci.h>#include "sysdep.h"static u32 addresses[] = { PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5, 0};int pciregions_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *data){ int i, pos=0; int bus, devfn, is_multi = 0; unsigned char headertype, pribus, secbus; u16 vendorid, deviceid = 0; /* to print information about several buses, keep an array of them */ #define MAXNBUS 8 int buses[MAXNBUS] = {0,}; int lastbus = 0; /* only one bus, by default, bus 0 */ int busindex = 0; /* this macro helps keeping the following lines short */ #define PRINTF(fmt, args...) sprintf(buf+len, fmt, ## args) len=0; /* Loop through the devices (code not printed in the book) */ if (!pci_present()) return sprintf(buf, "PCI not available in this computer\n"); bus = buses[busindex]; /* first bus (bus 0) */ for (devfn=0; pos < PAGE_SIZE; devfn++) { struct pci_dev *dev = NULL; /* * A clean implementation * would have a separate function to dump a single bus, but i * preferred to keep it in one function to include part of it * in the book (the printed code is automagically extracted from * this file). * * Instead, I use a dirty trick to fold two loops in one. */ if (devfn > 0xff) { /* end of this bus */ if (busindex == lastbus) break; /* loop over to the next bus */ bus = buses[++busindex]; devfn = 0; } /* * This code is derived from "drivers/pci/pci.c" in version * 2.0, although it has been modified to work with the 2.4 interface. * This means that the GPL applies to this source file * and credit is due to the original authors * (Drew Eckhardt, Frederic Potter, David Mosberger-Tang) */ if (PCI_FUNC(devfn) && !is_multi) /* not multi-function */ continue; dev = pci_find_slot(bus, devfn); if (!dev) { if (!PCI_FUNC(devfn)) is_multi = 0; /* no first implies no other */ continue; /* no such device */ } pci_read_config_byte(dev, PCI_HEADER_TYPE, &headertype); if (!PCI_FUNC(devfn)) /* first function */ is_multi = headertype & 0x80; headertype &= 0x7f; /* mask multi-function bit */ /* FIXME: should get rid of the PAGE_SIZE limit */ if (len > PAGE_SIZE / 2) { /* a big margin, just to be sure */ *eof = 1; return len; } vendorid = dev->vendor; deviceid = dev->device; len += PRINTF("Bus %i, device %2i, devfn %2i (id %04x-%04x," " headertype 0x%02x)\n", bus, devfn>>3, devfn & 7, vendorid, deviceid, headertype); if (headertype == PCI_HEADER_TYPE_BRIDGE) { /* This is a bridge, print what it does */ pci_read_config_byte(dev, PCI_PRIMARY_BUS, &pribus); pci_read_config_byte(dev, PCI_SECONDARY_BUS, &secbus); len += PRINTF("\tbridge connecting PCI bus %i to PCI bus %i\n", secbus, pribus); /* remember about this bus, to dump it later */ if (lastbus <= MAXNBUS-1) { lastbus++; buses[lastbus] = secbus; len += PRINTF("\t(bus %i is dumped below)\n", secbus); } else { len += PRINTF("\t(bus %i won't be dumped)\n", secbus); } pci_release_device(dev); /* 2.0 compatibility */ continue; } else if (headertype == PCI_HEADER_TYPE_CARDBUS) { /* This is a CardBus bridge, print what it does */ pci_read_config_byte(dev, PCI_CB_PRIMARY_BUS,&pribus); pci_read_config_byte(dev, PCI_CB_CARD_BUS,&secbus); len += PRINTF("\tbridge connecting CardBus %i to PCI bus %i\n", secbus, pribus); pci_release_device(dev); /* 2.0 compatibility */ continue; } else if (headertype != PCI_HEADER_TYPE_NORMAL) { len += PRINTF("\tunknown header type, skipping\n"); pci_release_device(dev); /* 2.0 compatibility */ continue; } /* Print the address regions of this device */ for (i=0; addresses[i]; i++) { u32 curr, mask, size; char *type; pci_read_config_dword(dev, addresses[i],&curr); cli(); pci_write_config_dword(dev, addresses[i],~0); pci_read_config_dword(dev, addresses[i],&mask); pci_write_config_dword(dev, addresses[i],curr); sti(); if (!mask) continue; /* there may be other regions */ /* * apply the I/O or memory mask to current position * note that I/O is limited to 0xffff, and 64-bit is not * supported by this simple imeplementation */ if (curr & PCI_BASE_ADDRESS_SPACE_IO) { curr &= PCI_BASE_ADDRESS_IO_MASK; } else { curr &= PCI_BASE_ADDRESS_MEM_MASK; } len += PRINTF("\tregion %i: mask 0x%08lx, now at 0x%08lx\n", i, (unsigned long)mask, (unsigned long)curr); /* extract the type, and the programmable bits */ if (mask & PCI_BASE_ADDRESS_SPACE_IO) { type = "I/O"; mask &= PCI_BASE_ADDRESS_IO_MASK; size = (~mask + 1) & 0xffff; /* Bleah */ } else { type = "mem"; mask &= PCI_BASE_ADDRESS_MEM_MASK; size = ~mask + 1; } len += PRINTF("\tregion %i: type %s, size %i (%i%s)\n", i, type, size, (size & 0xfffff) == 0 ? size >> 20 : (size & 0x3ff) == 0 ? size >> 10 : size, (size & 0xfffff) == 0 ? "MB" : (size & 0x3ff) == 0 ? "KB" : "B"); if (len > PAGE_SIZE / 2) { len += PRINTF("... more info skipped ...\n"); *eof = 1; return len; } } pci_release_device(dev); /* 2.0 compatibility */ } /* devfn */ *eof = 1; return len;}#ifdef USE_PROC_REGISTERstatic int pciregions_old_read_proc(char *buf, char **start, off_t offset, int len, int unused){ int eof; return pciregions_read_proc(buf, start, offset, len, &eof, NULL);}struct proc_dir_entry pciregions_proc_entry = { 0, /* low_ino: the inode -- dynamic */ 10, "pciregions", /* len of name and name */ S_IFREG | S_IRUGO, /* mode */ 1, 0, 0, /* nlinks, owner, group */ 0, NULL, /* size - unused; operations -- use default */ &pciregions_old_read_proc, /* function used to read data */ /* nothing more */ };#endif /* USE_PROC_REGISTER */int init_module(void){#ifdef USE_PROC_REGISTER proc_register_dynamic(&proc_root, &pciregions_proc_entry);#else create_proc_read_entry("pciregions", 0, NULL, pciregions_read_proc, NULL);#endif return 0;}void cleanup_module(void){#ifdef USE_PROC_REGISTER proc_unregister(&proc_root, pciregions_proc_entry.low_ino);#else remove_proc_entry("pciregions", 0);#endif}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -