1 /* 2 * The PCI Library -- Reading of Bus Dumps 3 * 4 * Copyright (c) 1997--2004 Martin Mares <[email protected]> 5 * 6 * Can be freely distributed and used under the terms of the GNU GPL. 7 */ 8 9 #include <stdio.h> 10 #include <ctype.h> 11 #include <string.h> 12 #include <errno.h> 13 14 #include "internal.h" 15 16 struct dump_data { 17 int len; 18 byte data[1]; 19 }; 20 21 static int 22 dump_detect(struct pci_access *a) 23 { 24 return !!a->method_params[PCI_ACCESS_DUMP]; 25 } 26 27 static void 28 dump_alloc_data(struct pci_dev *dev, int len) 29 { 30 struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1); 31 dd->len = len; 32 memset(dd->data, 0xff, len); 33 dev->aux = dd; 34 } 35 36 static void 37 dump_init(struct pci_access *a) 38 { 39 char *name = a->method_params[PCI_ACCESS_DUMP]; 40 FILE *f; 41 char buf[256]; 42 struct pci_dev *dev = NULL; 43 int len, mn, bn, dn, fn, i, j; 44 45 if (!a) 46 a->error("dump: File name not given."); 47 if (!(f = fopen(name, "r"))) 48 a->error("dump: Cannot open %s: %s", name, strerror(errno)); 49 while (fgets(buf, sizeof(buf)-1, f)) 50 { 51 char *z = strchr(buf, '\n'); 52 if (!z) 53 a->error("dump: line too long or unterminated"); 54 *z-- = 0; 55 if (z >= buf && *z == '\r') 56 *z-- = 0; 57 len = z - buf + 1; 58 mn = 0; 59 if ((len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' && 60 sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3) || 61 (len >= 13 && buf[4] == ':' && buf[7] == ':' && buf[10] == '.' && buf[12] == ' ' && 62 sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)) 63 { 64 dev = pci_get_dev(a, mn, bn, dn, fn); 65 dump_alloc_data(dev, 256); 66 pci_link_dev(a, dev); 67 } 68 else if (!len) 69 dev = NULL; 70 else if (dev && 71 (len >= 51 && buf[2] == ':' && buf[3] == ' ' || len >= 52 && buf[3] == ':' && buf[4] == ' ') && 72 sscanf(buf, "%x: ", &i) == 1) 73 { 74 struct dump_data *dd = dev->aux; 75 z = strchr(buf, ' '); 76 while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2])) 77 { 78 z++; 79 if (sscanf(z, "%x", &j) != 1 || i >= 256) 80 a->error("dump: Malformed line"); 81 if (i >= 4096) 82 break; 83 if (i > dd->len) /* Need to re-allocate the buffer */ 84 { 85 dump_alloc_data(dev, 4096); 86 memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256); 87 pci_mfree(dd); 88 dd = dev->aux; 89 } 90 dd->data[i++] = j; 91 z += 2; 92 } 93 } 94 } 95 } 96 97 static void 98 dump_cleanup(struct pci_access *a UNUSED) 99 { 100 } 101 102 static void 103 dump_scan(struct pci_access *a UNUSED) 104 { 105 } 106 107 static int 108 dump_read(struct pci_dev *d, int pos, byte *buf, int len) 109 { 110 struct dump_data *dd; 111 if (!(dd = d->aux)) 112 { 113 struct pci_dev *e = d->access->devices; 114 while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func)) 115 e = e->next; 116 if (!e) 117 return 0; 118 dd = e->aux; 119 } 120 if (pos + len > dd->len) 121 return 0; 122 memcpy(buf, dd->data + pos, len); 123 return 1; 124 } 125 126 static int 127 dump_write(struct pci_dev *d UNUSED, int pos UNUSED, byte *buf UNUSED, int len UNUSED) 128 { 129 d->access->error("Writing to dump files is not supported."); 130 return 0; 131 } 132 133 static void 134 dump_cleanup_dev(struct pci_dev *d) 135 { 136 if (d->aux) 137 { 138 pci_mfree(d->aux); 139 d->aux = NULL; 140 } 141 } 142 143 struct pci_methods pm_dump = { 144 "dump", 145 NULL, /* config */ 146 dump_detect, 147 dump_init, 148 dump_cleanup, 149 dump_scan, 150 pci_generic_fill_info, 151 dump_read, 152 dump_write, 153 NULL, /* init_dev */ 154 dump_cleanup_dev 155 }; 156