pciregions.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * pciregions.c --  a module that prints address regions of PCI devices
  3.  *
  4.  * $Id: pciregions.c,v 1.9 2001/03/16 11:30:23 rubini Exp $
  5.  *
  6.  * Copyright (C) 1997,2001   rubini@linux.it (Alessandro Rubini)
  7.  *
  8.  *   This program is free software; you can redistribute it and/or modify
  9.  *   it under the terms of the GNU General Public License as published by
  10.  *   the Free Software Foundation; either version 2 of the License, or
  11.  *   (at your option) any later version.
  12.  *
  13.  *   This program is distributed in the hope that it will be useful,
  14.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *   GNU General Public License for more details.
  17.  *
  18.  *   You should have received a copy of the GNU General Public License
  19.  *   along with this program; if not, write to the Free Software
  20.  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  21.  */
  22. #ifndef __KERNEL__
  23. #  define __KERNEL__
  24. #endif
  25. #ifndef MODULE
  26. #  define MODULE
  27. #endif
  28. #include <linux/config.h>
  29. #include <linux/module.h>
  30. #include <linux/sched.h>
  31. #include <linux/delay.h>
  32. #include <linux/proc_fs.h>
  33. #include <linux/pci.h>
  34. #include "sysdep.h"
  35. static u32 addresses[] = {
  36.     PCI_BASE_ADDRESS_0,
  37.     PCI_BASE_ADDRESS_1,
  38.     PCI_BASE_ADDRESS_2,
  39.     PCI_BASE_ADDRESS_3,
  40.     PCI_BASE_ADDRESS_4,
  41.     PCI_BASE_ADDRESS_5,
  42.     0
  43. };
  44. int pciregions_read_proc(char *buf, char **start, off_t offset,
  45.                    int len, int *eof, void *data)
  46. {
  47.     int i, pos=0;
  48.     int bus, devfn, is_multi = 0;
  49.     unsigned char headertype, pribus, secbus;
  50.     u16 vendorid, deviceid = 0;
  51.     /* to print information about several buses, keep an array of them */
  52.     #define MAXNBUS 8
  53.     int buses[MAXNBUS] = {0,};
  54.     int lastbus = 0; /* only one bus, by default, bus 0 */
  55.     int busindex = 0;
  56.     /* this macro helps keeping the following lines short */
  57.     #define PRINTF(fmt, args...) sprintf(buf+len, fmt, ## args)
  58.     len=0;
  59.     /* Loop through the devices (code not printed in the book) */
  60.     if (!pci_present())
  61.         return sprintf(buf, "PCI not available in this computern");
  62.     bus = buses[busindex]; /* first bus (bus 0) */
  63.     for (devfn=0; pos < PAGE_SIZE; devfn++) {
  64. struct pci_dev *dev = NULL;
  65. /*
  66.  * A clean implementation
  67.  * would have a separate function to dump a single bus, but i
  68.  * preferred to keep it in one function to include part of it
  69.  * in the book (the printed code is automagically extracted from
  70.  * this file).
  71.  *
  72.  * Instead, I use a dirty trick to fold two loops in one.
  73.  */
  74. if (devfn > 0xff) { /* end of this bus */
  75.     if (busindex == lastbus) break; 
  76.     /* loop over to the next bus */
  77.     bus = buses[++busindex];
  78.     devfn = 0;
  79. }
  80. /*
  81.  * This code is derived from "drivers/pci/pci.c" in version
  82.  * 2.0, although it has been modified to work with the 2.4 interface.
  83.  * This means that the GPL applies to this source file
  84.  * and credit is due to the original authors
  85.  * (Drew Eckhardt, Frederic Potter, David Mosberger-Tang)
  86.  */
  87.         if (PCI_FUNC(devfn) && !is_multi) /* not multi-function */
  88.     continue;
  89. dev = pci_find_slot(bus, devfn);
  90. if (!dev) {
  91.     if (!PCI_FUNC(devfn)) is_multi = 0; /* no first implies no other */
  92.     continue; /* no such device */
  93. }
  94. pci_read_config_byte(dev, PCI_HEADER_TYPE, &headertype);
  95.         if (!PCI_FUNC(devfn)) /* first function */
  96.     is_multi = headertype & 0x80;
  97. headertype &= 0x7f; /* mask multi-function bit */
  98. /* FIXME: should get rid of the PAGE_SIZE limit */
  99.         if (len > PAGE_SIZE / 2) { /* a big margin, just to be sure */
  100.     *eof = 1; return len;
  101. }
  102. vendorid = dev->vendor;
  103. deviceid = dev->device;
  104.         len += PRINTF("Bus %i, device %2i, devfn %2i (id %04x-%04x,"
  105.       " headertype 0x%02x)n",
  106.       bus, devfn>>3, devfn & 7,
  107.       vendorid, deviceid, headertype);
  108. if (headertype == PCI_HEADER_TYPE_BRIDGE) {
  109.     /* This is a bridge, print what it does */
  110.     pci_read_config_byte(dev, PCI_PRIMARY_BUS, &pribus);
  111.     pci_read_config_byte(dev, PCI_SECONDARY_BUS, &secbus);
  112.     len += PRINTF("tbridge connecting PCI bus %i to PCI bus %in",
  113.   secbus, pribus);
  114.     /* remember about this bus, to dump it later */
  115.     if (lastbus <= MAXNBUS-1) {
  116. lastbus++;
  117. buses[lastbus] = secbus;
  118. len += PRINTF("t(bus %i is dumped below)n", secbus);
  119.     } else {
  120. len += PRINTF("t(bus %i won't be dumped)n", secbus);
  121.     }
  122.     pci_release_device(dev); /* 2.0 compatibility */
  123.     continue;
  124. } else if (headertype == PCI_HEADER_TYPE_CARDBUS) {
  125.     /* This is a CardBus bridge, print what it does */
  126.     pci_read_config_byte(dev, PCI_CB_PRIMARY_BUS,&pribus);
  127.     pci_read_config_byte(dev, PCI_CB_CARD_BUS,&secbus);
  128.     len += PRINTF("tbridge connecting CardBus %i to PCI bus %in",
  129.   secbus, pribus);
  130.     pci_release_device(dev); /* 2.0 compatibility */
  131.     continue;
  132. } else if (headertype != PCI_HEADER_TYPE_NORMAL) {
  133.     len += PRINTF("tunknown header type, skippingn");
  134.     pci_release_device(dev); /* 2.0 compatibility */
  135.     continue;
  136. }
  137.         /* Print the address regions of this device */
  138.         for (i=0; addresses[i]; i++) {
  139.             u32 curr, mask, size;
  140.             char *type;
  141.             pci_read_config_dword(dev, addresses[i],&curr);
  142.             cli();
  143.             pci_write_config_dword(dev, addresses[i],~0);
  144.             pci_read_config_dword(dev, addresses[i],&mask);
  145.             pci_write_config_dword(dev, addresses[i],curr);
  146.             sti();
  147.             if (!mask)
  148. continue; /* there may be other regions */
  149.     /*
  150.      * apply the I/O or memory mask to current position
  151.      * note that I/O is limited to 0xffff, and 64-bit is not
  152.      * supported by this simple imeplementation
  153.      */
  154.     if (curr & PCI_BASE_ADDRESS_SPACE_IO) {
  155. curr &= PCI_BASE_ADDRESS_IO_MASK;
  156.     } else {
  157. curr &= PCI_BASE_ADDRESS_MEM_MASK;
  158.     }
  159.             len += PRINTF("tregion %i: mask 0x%08lx, now at 0x%08lxn", i,
  160.                            (unsigned long)mask,
  161.                            (unsigned long)curr);
  162.             /* extract the type, and the programmable bits */
  163.             if (mask & PCI_BASE_ADDRESS_SPACE_IO) {
  164.                 type = "I/O"; mask &= PCI_BASE_ADDRESS_IO_MASK;
  165. size = (~mask + 1) & 0xffff; /* Bleah */
  166.             } else {
  167.                 type = "mem"; mask &= PCI_BASE_ADDRESS_MEM_MASK;
  168. size = ~mask + 1;
  169.             }
  170.             len += PRINTF("tregion %i: type %s, size %i (%i%s)n", i,
  171.                           type, size,
  172.   (size & 0xfffff) == 0 ? size >> 20 :
  173.     (size & 0x3ff) == 0 ? size >> 10 : size,
  174.   (size & 0xfffff) == 0 ? "MB" :
  175.     (size & 0x3ff) == 0 ? "KB" : "B");
  176.     if (len > PAGE_SIZE / 2) {
  177. len += PRINTF("... more info skipped ...n");
  178. *eof = 1; return len;
  179.     }
  180.         }
  181. pci_release_device(dev); /* 2.0 compatibility */
  182.     } /* devfn */
  183.     *eof = 1;
  184.     return len;
  185. }
  186. #ifdef USE_PROC_REGISTER
  187. static int pciregions_old_read_proc(char *buf, char **start, off_t offset,
  188.  int len, int unused)
  189. {
  190.     int eof;
  191.     return pciregions_read_proc(buf, start, offset, len, &eof, NULL);
  192. }
  193. struct proc_dir_entry pciregions_proc_entry = {
  194.         0,                 /* low_ino: the inode -- dynamic */
  195.        10, "pciregions",   /* len of name and name */
  196.         S_IFREG | S_IRUGO, /* mode */
  197.         1, 0, 0,           /* nlinks, owner, group */
  198.         0, NULL,           /* size - unused; operations -- use default */
  199.         &pciregions_old_read_proc,   /* function used to read data */
  200.         /* nothing more */
  201.     };
  202. #endif /* USE_PROC_REGISTER */
  203. int init_module(void)
  204. {
  205. #ifdef USE_PROC_REGISTER
  206.     proc_register_dynamic(&proc_root, &pciregions_proc_entry);
  207. #else
  208.     create_proc_read_entry("pciregions", 0, NULL, pciregions_read_proc, NULL);
  209. #endif
  210.     return 0;
  211. }
  212. void cleanup_module(void)
  213. {
  214. #ifdef USE_PROC_REGISTER
  215.     proc_unregister(&proc_root, pciregions_proc_entry.low_ino);
  216. #else
  217.     remove_proc_entry("pciregions", 0);
  218. #endif
  219. }