summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-10-25 23:37:04 +0200
committerGerd Hoffmann <kraxel@redhat.com>2012-10-25 23:37:04 +0200
commit6a48ac4ef78d865faa2011f26874ddd1da5071ac (patch)
tree818ca5247926c33cda4fb78862fb05e5e3d2444c
downloadusb-tools-6a48ac4ef78d865faa2011f26874ddd1da5071ac.tar.gz
initial revision
-rw-r--r--.gitignore1
-rw-r--r--Makefile12
-rw-r--r--usb-print-caps.c255
3 files changed, 268 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..819a290
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+usb-print-caps
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..12a6610
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+
+CC ?= gcc
+CFLAGS ?= -Os
+CFLAGS += -Wall
+
+TARGETS := usb-print-caps
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *~
diff --git a/usb-print-caps.c b/usb-print-caps.c
new file mode 100644
index 0000000..fac3b99
--- /dev/null
+++ b/usb-print-caps.c
@@ -0,0 +1,255 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+/* ------------------------------------------------------------- */
+
+#define BASEPATH "/sys/bus/pci/devices"
+
+void *mapbar(char *dev, int bar)
+{
+ char filename[128];
+ struct stat st;
+ void *map;
+ int fd;
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s/resource%d", BASEPATH, dev, bar);
+ fd = open(filename, O_RDONLY);
+ if (-1 == fd) {
+ fprintf(stderr, "open %s: %s", filename, strerror(errno));
+ return NULL;
+ }
+ fstat(fd, &st);
+
+ map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (MAP_FAILED == map) {
+ fprintf(stderr, "mmap %s: %s", filename, strerror(errno));
+ return NULL;
+ }
+
+ close(fd);
+ return map;
+}
+
+uint32_t readsys(char *dev, char *file)
+{
+ char filename[128], content[128];
+ FILE *fp;
+
+ snprintf(filename, sizeof(filename),
+ "%s/%s/%s", BASEPATH, dev, file);
+ fp = fopen(filename, "r");
+ if (NULL == fp)
+ return 0;
+ fgets(content, sizeof(content), fp);
+ fclose(fp);
+ return strtol(content, NULL, 0);
+}
+
+/* ------------------------------------------------------------- */
+
+static const char *xhci_capname[] = {
+ [ 0 ] = "Reserved",
+ [ 1 ] = "USB Legacy Support",
+ [ 2 ] = "Supported Protocol",
+ [ 3 ] = "Extended Power Management",
+ [ 4 ] = "I/O Virtualization",
+ [ 5 ] = "Message Interrupt",
+ [ 6 ] = "Local Memory",
+ [ 7 ... 9 ] = "Reserved",
+ [ 10 ] = "USB Debug Capability",
+ [ 11 ... 16 ] = "Reserved",
+ [ 17 ] = "Extended Message Interrupt",
+ [ 18 ... 191 ] = "Reserved",
+ [ 192 ... 255 ] = "Vendor Defined",
+};
+
+void xhcidump(char *dev)
+{
+ uint32_t *map, val;
+ int i, n, ext = 0, off, cid;
+
+ map = mapbar(dev, 0);
+ if (!map)
+ return;
+
+ n = map[0] & 0xff;
+ if (n > 0x20)
+ n = 0x20;
+ printf(" xhci base caps\n");
+ for (i = 0; i * 4 < n; i++) {
+ val = map[i];
+ printf(" 0x%04x: 0x%08x", i * 4, val);
+ switch (i * 4) {
+ case 0x00:
+ printf(" - version %x.%02x, caplength 0x%x",
+ (val >> 24) & 0xff, (val >> 16) & 0xff, val & 0xff);
+ break;
+ case 0x04:
+ printf(" - ports %d, intrs %d, slots %d",
+ (val >> 24) & 0xff, (val >> 8) & 0x3ff, val & 0xff);
+ break;
+ case 0x08:
+ printf(" - erst max 0x%x, ist 0x%x",
+ (val >> 4) & 0x0f, val & 0x0f);
+ break;
+ case 0x0c:
+ printf(" - u2 lat 0x%x, u1 lat 0x%x",
+ (val >> 16) & 0xffff, val & 0xff);
+ break;
+ case 0x10:
+ ext = (val >> 16) & 0xffff;
+ printf(" - extptr 0x%x, maxpsasize 0x%x%s%s%s%s%s%s%s%s",
+ ext, (val >> 12) & 0xf,
+ (val & 0x80) ? ", nss" : "",
+ (val & 0x40) ? ", ltc" : "",
+ (val & 0x20) ? ", lhrc" : "",
+ (val & 0x10) ? ", pind" : "",
+ (val & 0x08) ? ", ppc" : "",
+ (val & 0x04) ? ", csz" : "",
+ (val & 0x02) ? ", bnc" : "",
+ (val & 0x01) ? ", ac64" : "");
+ break;
+ case 0x14:
+ printf(" - doorbell offset 0x%x", val);
+ break;
+ case 0x18:
+ printf(" - runtime offset 0x%x", val);
+ break;
+ default:
+ break;
+ }
+ printf("\n");
+ }
+
+ while (ext) {
+ printf(" xhci ext cap @ 0x%x\n", ext*4);
+ val = map[ext];
+ off = val >> 8 & 0xff;
+ cid = val & 0xff;
+ printf(" 0x%04x: 0x%08x - next 0x%x, cap 0x%x [ %s ]\n",
+ ext*4, val, off, cid, xhci_capname[cid]);
+ switch (cid) {
+ case 2:
+ printf(" - version %x.%02x\n",
+ (val >> 24) & 0xff, (val >> 16) & 0xff);
+ val = map[ext+1];
+ printf(" 0x%04x: 0x%08x - name %c%c%c%c\n",
+ ext*4+4, val, val & 0xff, (val >> 8) & 0xff,
+ (val >> 16) & 0xff, (val >> 24) & 0xff);
+ val = map[ext+2];
+ printf(" 0x%04x: 0x%08x - psic 0x%x, port count %d, port offset %d\n",
+ ext*4+8, val, (val >> 28) & 0xf, (val >> 8) & 0xff, val & 0xff);
+ break;
+ }
+ if (off) {
+ ext += off;
+ } else {
+ ext = 0;
+ }
+ }
+ return;
+}
+
+/* ------------------------------------------------------------- */
+
+void ehcidump(char *dev)
+{
+ uint32_t *map, val;
+ int i, n;
+
+ map = mapbar(dev, 0);
+ if (!map)
+ return;
+
+ n = map[0] & 0xff;
+ if (n > 0x10)
+ n = 0x10;
+ printf(" ehci caps\n");
+ for (i = 0; i * 4 < n; i++) {
+ val = map[i];
+ printf(" 0x%04x: 0x%08x", i * 4, val);
+ switch (i * 4) {
+ case 0x00:
+ printf(" - version %x.%02x, caplength 0x%x",
+ (val >> 24) & 0xff, (val >> 16) & 0xff, val & 0xff);
+ break;
+ case 0x04:
+ printf(" - dbg port %d%s, companion %d ctl %d prt%s, ports %d",
+ (val >> 20) & 0x0f,
+ (val >> 16) & 0x01 ? ", pi" : "",
+ (val >> 12) & 0x0f,
+ (val >> 8) & 0x0f,
+ (val >> 4) & 0x01 ? ", ppc" : "",
+ (val >> 0) & 0x07);
+ break;
+ case 0x08:
+ printf(" - extptr 0x%x, iso thresh %d%s%s%s",
+ (val >> 8) & 0xff,
+ (val >> 4) & 0x0f,
+ (val >> 2) & 0x01 ? ", aspc" : "",
+ (val >> 1) & 0x01 ? ", pflf" : "",
+ (val >> 0) & 0x01 ? ", 64ac" : "");
+ break;
+ default:
+ break;
+ }
+ printf("\n");
+ }
+
+ return;
+}
+
+/* ------------------------------------------------------------- */
+
+int main(int argc, char *argv[])
+{
+ unsigned long addr0;
+ struct dirent *entry;
+ uint32_t class, vendor, device;
+ DIR *dir;
+
+ dir = opendir(BASEPATH);
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_name[0] == '.')
+ continue;
+ if (argc > 1 && !strstr(entry->d_name, argv[1]))
+ continue;
+ class = readsys(entry->d_name, "class");
+ vendor = readsys(entry->d_name, "vendor");
+ device = readsys(entry->d_name, "device");
+ addr0 = readsys(entry->d_name, "resource");
+ switch (class) {
+ case 0x0c0300:
+ printf("uhci @ %s %04x:%04x\n", entry->d_name, vendor, device);
+ break;
+ case 0x0c0310:
+ printf("ohci @ %s %04x:%04x\n", entry->d_name, vendor, device);
+ break;
+ case 0x0c0320:
+ printf("ehci @ %s %04x:%04x\n", entry->d_name, vendor, device);
+ printf(" bar0 @ 0x%lx\n", addr0);
+ if (addr0 & 0xfff) {
+ printf(" Oops, not page aligned, skipping\n");
+ } else {
+ ehcidump(entry->d_name);
+ }
+ break;
+ case 0x0c0330:
+ printf("xhci @ %s %04x:%04x\n", entry->d_name, vendor, device);
+ printf(" bar0 @ 0x%lx\n", addr0);
+ xhcidump(entry->d_name);
+ break;
+ }
+ }
+ return 0;
+}