⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pciregions.c

📁 ldd1的源代码
💻 C
字号:
/* * pciregions.c --  a module that prints address regions of PCI devices * * $Id: pciregions.c,v 1.2 2000/06/12 16:02:32 rubini Exp $ * Tested with 2.0.36 on the x86 * Tested with 2.2.16 on the x86 * Tested with 2.2.13 on the Netwinder * * Copyright (C) 1997,2000   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., 675 Mass Ave, Cambridge, MA 02139, USA. */#ifndef __KERNEL__#  define __KERNEL__#endif#ifndef MODULE#  define MODULE#endif#include <linux/module.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/pci.h>#include "sysdep.h"#ifdef LINUX_24#  warning "This module has only been compiled and tested with kernels 2.0/2.2"#endif#ifndef PCI_HEADER_TYPE_NORMAL /* These definitions are missing from 2.0 */#  define PCI_HEADER_TYPE_NORMAL 0#  define PCI_HEADER_TYPE_BRIDGE 1#  define   PCI_PRIMARY_BUS         0x18    /* Primary bus number */#  define   PCI_SECONDARY_BUS       0x19    /* Secondary bus number */#  define   PCI_SUBORDINATE_BUS     0x1a    /* Highest bus behind the bridge */#  define PCI_HEADER_TYPE_CARDBUS 2#  define   PCI_CB_PRIMARY_BUS      0x18    /* PCI bus number */#  define   PCI_CB_CARD_BUS         0x19    /* CardBus bus number */#  define   PCI_CB_SUBORDINATE_BUS  0x1a    /* Subordinate bus number */#endifstatic 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, fun, is_multi = 0;    unsigned char headertype, pribus, secbus;    u32 longword;    u16 vendorid, deviceid;    /* 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;    #define PRINTF(fmt, args...) sprintf(buf+len, fmt, ## args)    len=0;    /* Loop through the devices (code not printed in the book) */    if (!pcibios_present())        return sprintf(buf, "No PCI bios present\n");    bus = buses[busindex]; /* first bus (bus 0) */    for (fun=0; pos < PAGE_SIZE; fun++) {	/*	 * 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 (fun > 0xff) { /* end of this bus */	    if (busindex == lastbus) break; 	    /* loop over to the next bus */	    bus = buses[++busindex];	    fun = 0;	}	/*	 * This code is derived from "drivers/pci/pci.c". 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(fun) && !is_multi) /* not multi-function */	    continue;		pcibios_read_config_byte(bus, fun, PCI_HEADER_TYPE, &headertype);        if (!PCI_FUNC(fun)) /* first function */	    is_multi = headertype & 0x80;	headertype &= 0x7f; /* mask multi-function bit */        pcibios_read_config_dword(bus,fun,PCI_VENDOR_ID, &longword);        if (longword == 0xffffffff || longword == 0x00000000) {            is_multi = 0; continue;        }        	/* FIXME: should get rid of the PAGE_SIZE limit */        if (len > PAGE_SIZE - 160) { /* a big margin, just to be sure */	    *eof = 1; return len;	}        pcibios_read_config_word(bus,fun,PCI_VENDOR_ID,&vendorid);        pcibios_read_config_word(bus,fun,PCI_DEVICE_ID,&deviceid);        len += PRINTF("Bus %i, device %2i, fun %2i (id %04x-%04x,"		      " headertype 0x%02x)\n",		      bus, fun>>3, fun & 7,		      vendorid, deviceid, headertype);	if (headertype == PCI_HEADER_TYPE_BRIDGE) {	    /* This is a bridge, print what it does */	    pcibios_read_config_byte(bus,fun,PCI_PRIMARY_BUS,&pribus);	    pcibios_read_config_byte(bus,fun,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);	    }	    continue;	} else if (headertype == PCI_HEADER_TYPE_CARDBUS) {	    /* This is a CardBus bridge, print what it does */	    pcibios_read_config_byte(bus,fun,PCI_CB_PRIMARY_BUS,&pribus);	    pcibios_read_config_byte(bus,fun,PCI_CB_CARD_BUS,&secbus);	    len += PRINTF("\tbridge connecting CardBus %i to PCI bus %i\n",			  secbus, pribus);	    continue;	} else if (headertype != PCI_HEADER_TYPE_NORMAL) {	    len += PRINTF("\tunknown header type, skipping\n");	    continue;	}		        /* Print the address regions of this device */        for (i=0; addresses[i]; i++) {            u32 curr, mask;            char *type;            pcibios_read_config_dword(bus,fun,addresses[i],&curr);            cli();            pcibios_write_config_dword(bus,fun,addresses[i],~0);            pcibios_read_config_dword(bus,fun,addresses[i],&mask);            pcibios_write_config_dword(bus,fun,addresses[i],curr);            sti();            if (!mask)		continue; /* there may be other regions */	    /* apply the I/O or memory mask to current position */	    /* FIXME: handle 64-bit regiorns */	    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;            } else {                type = "mem"; mask &= PCI_BASE_ADDRESS_MEM_MASK;            }            len += PRINTF("\tregion %i: type %s, size %i\n", i,                          type, ~mask+1);	    if (len > PAGE_SIZE - 160) {		*eof = 1; return len;	    }        }    } /* fun */    *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}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -