/* * pcibustype.c: returns the PCI bus type ('pci', 'agp', or 'pcie') of the * given device. * * If you actually need to use this, odds are you're doing something deeply * wrong. * * Author: Daniel Stone * * Copyright © 2005 Canonical Ltd * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software. * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * CANONICAL LTD BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, BUT NOT LIMITED * TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include #include #include #include #define PCI_STATUS 0x04 #define PCI_CAPABILITY_LIST 0x34 #define PCI_CAP_LIST_MASK 0x100000 #define CAP_RESERVED_BITS 0xfc #define PCI_CAP_ID_AGP 0x02 /* the PCIE bit isn't listed in my version of linux/pci.h */ #define PCI_CAP_ID_PCIE 0x10 #define PCI_CAPABILITY_BIT_MASK 0xff #ifdef DEBUG # define dprintf printf #else # define dprintf(x, ...) /**/ #endif /* PCI stuff will always be little-endian, so we want to swap it to the host's * endianness. */ #if __BYTE_ORDER == __LITTLE_ENDIAN # define HOST_ORDER(bit) (bit) #else # define HOST_ORDER(bit) (((bit >> 24) & 0x000000ff) | \ ((bit >> 8) & 0x0000ff00) | \ ((bit << 8) & 0x00ff0000) | \ ((bit << 24) & 0xff000000)) #endif #define CAP(bit) (bit & PCI_CAPABILITY_BIT_MASK) unsigned int pciRead(int fd, int offset) { unsigned int bit = 0xffffffff; lseek(fd, offset, SEEK_SET); if ((read(fd, &bit, 4)) != 4) { fprintf(stderr, "failed reading from offset %d\n", offset); return -1; } dprintf("[pciRead] returning %.8lx\n", bit); return HOST_ORDER(bit); } /* TODO: domain support */ char *pciFile(const char *busid) { char *filename, *tmp; int bus, dev, func; if (strncmp(busid, "PCI:", 4) != 0) { fprintf(stderr, "bus type is not PCI\n"); return NULL; } tmp = (char *)malloc(sizeof(char) * strlen(busid)); if (!tmp) { fprintf(stderr, "failed to allocate tmp\n"); return NULL; } if (strncpy(tmp, busid, strlen(busid)) == NULL) { fprintf(stderr, "failed to copy busid to tmp\n"); return NULL; } tmp = strstr(tmp, ":"); bus = atoi(++tmp); tmp = strstr(tmp, ":"); dev = atoi(++tmp); tmp = strstr(tmp, ":"); func = atoi(++tmp); filename = (char *)malloc(sizeof(char) * strlen("/proc/bus/pci/00/00.0")); sprintf(filename, "/proc/bus/pci/%.2x/%.2x.%.1x", bus, dev, func); dprintf("[pciFile] returning %s\n", filename); return filename; } int main(int argc, char *argv[]) { int fd; unsigned int bit = 0xffffffff; unsigned int bitptr = 0xffffffff; char *pcifile; if (argc < 2) { fprintf(stderr, "usage: pcibustype [pcidev]\n"); return 1; } if ((pcifile = pciFile(argv[1])) == NULL) { fprintf(stderr, "couldn't parse bus ID string %s\n", argv[1]); return 1; } if ((fd = open(pcifile, O_RDONLY)) < 0) { fprintf(stderr, "couldn't open PCI file %s\n", pcifile); return 1; } if ((bit = pciRead(fd, PCI_STATUS)) == -1) { fprintf(stderr, "couldn't read the caplist long\n"); return 1; } if ((bit & PCI_CAP_LIST_MASK)) { dprintf("pci with extended caps, at least\n"); for (bitptr = pciRead(fd, PCI_CAPABILITY_LIST); \ bitptr != 0x00; bitptr = (bit >> 8)) { bitptr &= CAP_RESERVED_BITS; if (bitptr == -1 || bitptr == 0x00) { dprintf("bailing after bitptr %.2lx (%.2lx)\n", bitptr, bit); break; } dprintf("reading capability from %.2lx\n", bitptr); if ((bit = pciRead(fd, bitptr)) == -1) { fprintf(stderr, "couldn't read capability\n"); return 1; } if (CAP(bit) == PCI_CAP_ID_AGP) { printf("agp\n"); return 0; } else if (CAP(bit) == PCI_CAP_ID_PCIE) { printf("pcie\n"); return 0; } else { dprintf("cap bit is %.2lx\n", CAP(bit)); } } /* walked the entire list and no AGP/PCIE cap. must be PCI. */ dprintf("doesn't have agp/pcie capability\n"); printf("pci\n"); return 0; } else { dprintf("no extended capabilities\n"); printf("pci\n"); return 0; } /* not reached */ return 0; }